Значение параметра CreateThread неожиданно меняется - PullRequest
3 голосов
/ 23 января 2012

Я пытаюсь создать 4 потока для одновременного запуска функции на моих 4 процессорных ядрах. Функция, которую я вызываю, изменит некоторые смещения цикла в зависимости от val значения переменной.

Я пробовал это, но он не увеличивает счетчик val должным образом, некоторые потоки сообщают одинаковые значения, кажется, он меняется случайным образом:

int val = 1;
threads[0] = CreateThread(0, 0, my_thread_1, &val, 0, 0);
val++;
threads[1] = CreateThread(0, 0, my_thread_1, &val, 0, 0);
val++;
threads[2] = CreateThread(0, 0, my_thread_1, &val, 0, 0);
val++;
threads[3] = CreateThread(0, 0, my_thread_1, &val, 0, 0);

Но, похоже, это работает нормально:

int val1 = 1;
int val2 = 2;
int val3 = 3;
int val4 = 4;
threads[0] = CreateThread(0, 0, my_thread_1, &val1, 0, 0);
threads[1] = CreateThread(0, 0, my_thread_1, &val2, 0, 0);
threads[2] = CreateThread(0, 0, my_thread_1, &val3, 0, 0);
threads[3] = CreateThread(0, 0, my_thread_1, &val4, 0, 0);

В чем может быть причина этого, и как это правильно сделать, чтобы дать некоторый параметр потоку?

Это моя функция:

DWORD WINAPI my_thread_1(void *params){ 
    int val = *(int *)params;
...
}

Ответы [ 3 ]

5 голосов
/ 23 января 2012

Это происходит просто потому, что в вашем первом примере вы передаете указатель на одну и ту же ячейку памяти для всех 4 потоков. Тот факт, что вы увеличили значение перед передачей указателя , несущественен, поскольку область памяти остается прежней.

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

Вы можете немного реструктурировать свой код, чтобы помочь с удобством обслуживания и гибкостью:

int threadData[NTHREADS]; /* in the future this could be an array of structs */
HANDLE threads[NTHREADS];
int tt;

for (tt = 0; tt < NTHREADS; ++tt)
{
    threadData[tt] = tt + 1; /* placeholder for actual logic */
    threads[tt] = CreateThread(
        NULL,            /* lpThreadAttributes */
        0,               /* dwStackSize */
        my_thread_1,     /* lpStartAddress */
        &threadData[tt], /* lpParameter: each thread will receive its own data */
        0,               /* dwCreationFlags */
        NULL             /* lpThreadId */);
}

/* Since threadData and threads are local to the enclosing scope,
 * we must wait for them to finish here to ensure we don't read
 * data we no longer own
 */
WaitForMultipleObjects(NTHREADS, threads, TRUE, INFINITE);
1 голос
/ 23 января 2012

В первом случае вы передаете один и тот же объект всем потокам.Во втором случае вы передаете разные объекты.

В обоих случаях существует потенциальная проблема, заключающаяся в том, что если функция, создающая потоки, возвращает результат, то все созданные потоки будут иметь указатель на int, который небольше не существует, потому что все int объекты являются локальными объектами функции, создавшей потоки.Это вызывает неопределенное поведение.

Так что если функция не ждет и не возвращает, то в этом случае вам не следует передавать указатель на локальный объект, вместо этого передавать динамически размещенный объект:

int *v1 = new int;
threads[0] = CreateThread(0, 0, my_thread_1, v1 , 0, 0);
0 голосов
/ 23 января 2012

Несколько потоков одновременно обращаются к одной и той же памяти.Вы должны использовать мьютекс или семафор для монопольного доступа к переменной в критических секциях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...