Прочитайте учебник о pthreads . Вы не можете ожидать воспроизводимого поведения при доступе и изменении глобальных данных в нескольких потоках (без дополнительных мер предосторожности при кодировании, связанных с синхронизация ). AFAIU Ваш код демонстрирует некоторые хитрые неопределенное поведение , и вы должны быть напуганы (возможно, это только неопределенное поведение в вашем случае). Чтобы объяснить наблюдаемое конкретное поведение, вам нужно погрузиться в детали реализации (а у вас нет на это времени: изучить сгенерированный ассемблерный код, поведение вашего конкретного оборудования и т. Д.).
Также (поскольку info
является указателем на int
)
int calc = info;
не имеет большого смысла (я полагаю, вы сделали опечатку). В некоторых системах (например, в моем x86-64 под управлением Linux) указатель шире, чем int
(поэтому calc
теряет половину битов из info
). В других (редких) системах он может быть меньше по размеру. Иногда (i686 под управлением Linux) он может иметь такой же размер. Вам следует рассмотреть intptr_t
из <stdint.h>
, если вы хотите привести указатели к целым значениям и обратно.
На самом деле, вы должны защищать доступ к этим глобальным данным (внутри i
, возможно, доступ через указатель) с помощью mutex или использовать в C11 атомарных операциях с тех пор данные используются несколькими параллельными потоками.
Таким образом, вы можете объявить глобальный мьютекс, такой как
pthread_mutext_t mtx = PTHREAD_MUTEX_INITIALIZER;
(или используйте pthread_mutex_init ), тогда в вашем sum
вы наберете
pthread_mutex_lock(&mtx);
i = i + calc;
pthread_mutex_unlock(&mtx);
(см. Также pthread_mutex_lock и pthread_mutex_lock (3p) ). Конечно, вы должны также написать код в вашем main
.
Блокировка мьютекса стоит немного дороже (как правило, в несколько десятков раз больше, чем дополнение), даже если он был разблокирован. Вы можете рассмотреть атомарные операции, если вы можете кодировать в C11, так как вы имеете дело с целыми числами. Вы объявите atomic_int i;
и будете использовать atomic_load и atomic_fetch_add .
Если вам интересно, см. Также pthreads (7) & futex (7) .
Многопоточное программирование действительно сложно (для всех). Вы не можете ожидать, что поведение будет воспроизводимым в целом, и ваш код, очевидно, может вести себя так, как ожидалось, и все равно будет очень неправильным (и будет работать по-другому в некоторой другой системе). Читайте также о моделях памяти , кэш процессора , согласованность кэша , одновременных вычислений ...
Рассмотрите возможность использования средства очистки потока GCC. Опции инструментов и / или Valgrind helgrind