#c #multithreading #pthreads #mutex
#c #многопоточность #pthreads #мьютекс
Вопрос:
Я учусь pthreads
и mutex variables
, в частности. Я смотрю на пример кода, который вы можете найти здесь. Он использует потоки для вычисления скалярного произведения. Центральной частью кода является функция точечного произведения:
void *dotprod(void *arg)
{
int i, start, end, len ;
long offset;
double mysum, *x, *y;
offset = (long)arg;
len = dotstr.veclen;
start = offset*len;
end = start len;
x = dotstr.a;
y = dotstr.b;
mysum = 0;
for (i=start; i<end ; i )
{
mysum = (x[i] * y[i]);
}
/*
Lock a mutex prior to updating the value in the shared
structure, and unlock it upon updating.
*/
pthread_mutex_lock (amp;mutexsum);
dotstr.sum = mysum;
pthread_mutex_unlock (amp;mutexsum);
pthread_exit((void*) 0);
}
Первый вопрос заключается в том, действительно ли блокировка потоков здесь необходима. Я попробовал удалить вызовы блокировки и разблокировки, и конечный результат был тем же самым. Но это всего лишь пример, поэтому, возможно, на практике блокировки не нужны. Что подводит меня к моему второму вопросу: я подумал, что попытаюсь изменить код на что-то, результат чего может измениться в зависимости от того, обращаются ли несколько потоков dotstr.sum
. Я снова избавился от замка и попробовал:
dotstr.sum = mysum;
dotstr.sum *= 1.1;
Но, вопреки моим ожиданиям, это не привело к возникновению условия гонки. Результат был точно таким же в нескольких испытаниях. Почему это должно быть? Наконец, может ли кто-нибудь предложить простое изменение кода, в котором потребуется блокировка?
Комментарии:
1. Несинхронизированный доступ приводит к неопределенному поведению. Вы не можете ожидать какого-либо конкретного поведения для какого-либо конкретного запуска (например, мгновенного прерывания каждый раз).
2. «условие гонки» не означает, что потоки действительно мешали друг другу. Это означает, что потоки могут мешать друг другу.
3. Просто в качестве примечания: строка
offset = (long)arg;
не будет работать на некоторых платформах, таких как Microsoft Windows, гдеsizeof(long) == 4
иsizeof(void*) == 8
. Возможно, вы захотите рассмотреть возможность использованияuintptr_t
вместоlong
, поскольку этот тип был определен стандартом специально для хранения того же количества битов, что и указатель.4. Всегда существует вероятность того, что один поток будет выгружен (т. Е. Остановлен) в критической ситуации, так что другой поток выиграет гонку. Если вы хотите воспроизвести эту ситуацию, то вы можете добавить случайное поведение в более быстрый поток, например
if (rand()0==0) DoSomethingWhichCostsALotOfPerformance();
5. Посмотрите здесь .