Потоки в C прерывают друг друга - PullRequest
0 голосов
/ 29 апреля 2020

Итак, у меня есть глобальная переменная counter, и я запускаю 4 потока, которые увеличиваются в миллион раз, но результат, который я получаю в конце, даже не достигает 2 миллионов.

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>


int nthread;
int counter=0;
void *f(void *arg)
{
    int i = *(int *)arg;
    int *p;
   for (int c = 0; c < 1000000; c++)
   {
       counter++;
   }

    printf(" I am thread %d (out of %d),tid =% ld\n", i, nthread, pthread_self());
    p = malloc(sizeof(int));
    *p = i * 2;
    pthread_exit(p); // return p
}

int main(int argc, char *argv[])
{
    pthread_t *tid;
    int e, i, *ti;
    nthread = 4;
    tid = malloc(nthread * sizeof(pthread_t));
    ti = malloc(nthread * sizeof(int));
    for (i = 0; i < nthread; i++)
    {
        ti[i] = i;
        if ((e = pthread_create(&tid[i], NULL, f, &ti[i])) != 0)
            send_error(e, " pthread_create ");
    }
    for (i = 0; i < nthread; i++)
    {
        void *r;
        if ((e = pthread_join(tid[i], &r)) != 0)
            send_error(e, " pthread_join ");
        printf(" Return of thread %d = %d\n", i, *(int *)r);
        free(r);
    }
    printf("counter is %d\n",counter);
    free(tid);
    free(ti);
}

Что вызывает это и как я могу это исправить? PS: если ваш код не компилируется, замените send_error на printfs

1 Ответ

1 голос
/ 29 апреля 2020

Стандарты pthreads очень ясны, что вы не можете получить доступ к объекту в одном потоке, в то время как другой поток изменяет или может изменять его. Ваш код нарушает это правило.

Есть много причин для этого правила, но наиболее очевидным является следующее:

for (int c = 0; c < 1000000; c++)
{
    counter++;
}

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

приведет к тому, что огромное количество ценных оптимизаций станет невозможным для 99% кода, который не разделяет объекты между потоками, только потому, что компилятор не может доказать, что доступы могут перекрываться.

Это имеет гораздо больший смысл требуется код, который имеет перекрывающийся доступ к объекту, чтобы четко указывать, что они делают. И каждый стандарт потоков предоставляет хорошие способы сделать это, включая pthreads.

Вы можете использовать любой метод, чтобы предотвратить эту проблему, которая вам нравится. Использование мьютекса - самое простое и определенно то, чему вы должны научиться в первую очередь.

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