Опубликован: 28.10.2009 | Уровень: специалист | Доступ: платный
Лекция 6:

Отладка параллельной программы

9.7.4. Создание проекта в Intel Thread Checker

  1. Запустите Intel® Thread Checker. Найти его можно, например, по следующему пути: Start \to All programs \to Intel(R) Software Development Tools \to Intel(R) Thread Checker 3.0 \to Intel(R) Thread Checker.
  2. В открывшемся окне нажмите на кнопку New Project.
  3. В окне создания проекта выберите Intel ® Thread Checker Wizard и нажмите кнопку OK.
    Выбор типа проекта

    Рис. 9.12. Выбор типа проекта
  4. В окне мастера в поле Launch an application укажите путь к исполняемому файлу C:\ITCLabs\DataRaces\Debug\DataRaces.exe.
    Выбор программы для анализа

    Рис. 9.13. Выбор программы для анализа
  5. Нажмите кнопку Finish.

После этого запустится ITC, произведет инструментацию программы и начнет анализ.

9.7.5. Анализ собранной информации

По окончании процесса сбора информации ITC представит результаты в виде, показанном на рис. 9.14. Итак, мы видим, что ITC нашел в предложенном коде 3 ошибки. При ближайшем рассмотрении видно, что все они указывают на одну и ту же переменную globalX. Краткие комментарии к диагностикам показывают, что ITC указал все возможные комбинации неверного обращения к переменной globalX:

  • когда первый поток записывает новое значение в переменную globalX, а второй в это время читает из нее;
  • когда первый поток читает из переменной globalX,а второй в это время в нее пишет;
  • когда оба потока одновременно пишут в переменную globalX.

Несмотря на то, что реально работало 4 потока, очевидно, что для демонстрации ошибки достаточно двух. Именно так ITC всегда и комментирует гонки данных.

Результат анализа примера DataRaces - Diagnostics

увеличить изображение
Рис. 9.14. Результат анализа примера DataRaces - Diagnostics

При наличии отладочной информации ITC может показать в исходном коде местоположение ошибки. Выберите любую из найденных ошибок и двойным щелчком по ней перейдите к просмотру исходного кода (рис. 9.15).

Результат анализа примера DataRaces - Source View

увеличить изображение
Рис. 9.15. Результат анализа примера DataRaces - Source View

Комментарий в красном поле над исходными текстами описывает ситуацию. В представленном на рисунке случае имеет место конфликт доступа типа "запись-чтение".

9.7.6. Причина и устранение

Осталась самая малость - понять, в чем причина гонки данных в рассматриваемом примере, и устранить ее. Сделать это на самом деле не так уж сложно. Противоречие с тем фактом, что обращение потоков к переменной globalX происходит внутри критической секции, а гонка данных все равно имеется, кажущееся. Проблема в данном случае не в критической секции, а в объекте, на котором она основана ( CRITICAL_SECTION cs ). Этот объект объявлен внутри потоковой функции, а значит, является локальным для каждого потока. То есть, когда один поток захватывает критическую секцию, он делает это для своего локального объекта cs, к которому остальные потоки не имеют доступа.

Исправить ситуацию можно несколькими способами, но в любом из них объявление объекта cs нужно вынести из потоковой функции increment, а инициализацию секции и освобождение ресурсов поместить в функцию main.

Возможный корректный вариант представлен ниже.

#include <stdio.h>
#include <windows.h>

#define NTHREADS 4

int globalX = 0;
CRITICAL_SECTION cs;

DWORD WINAPI increment (void *arg)
{
  EnterCriticalSection (&cs);
    globalX++;
  LeaveCriticalSection (&cs);
	
  return 0;
}

int main (int argc, char *argv[])
{
  HANDLE h[NTHREADS];
  DWORD  rc;
  int i;

  printf ("START\n");

  InitializeCriticalSection (&cs);

  for (i = 0; i < NTHREADS; i++)
  {
    h[i] = CreateThread (0, 0, increment, NULL, 0, NULL);
  }

  rc = WaitForMultipleObjects (NTHREADS, h, TRUE, INFINITE);

  DeleteCriticalSection (&cs);

  printf ("TOTAL = %d\n", globalX);
  printf ("STOP\n");
}

9.8 Заключение

Ни для кого не секрет, наличие инструментов делает жизнь проще. Перефразируем: наличие Intel® Thread Checker существенно скрашивает суровые будни разработчика многопоточных программ. Убедиться в этом еще раз читатель сможет в лабораторной работе "Отладка параллельной программы с использованием Intel Thread Checker", в которой приводится дополнительная информация по ITC.

Алексей Николаев
Алексей Николаев
Россия, г. Саранск
Рамиль Ариков
Рамиль Ариков
Россия, Республика Мордовия