Мой цикл не выполняется должным образом в многопоточности

#c #multithreading #pthreads #pthread-join

#c #многопоточность #pthreads #pthread-join

Вопрос:

Я пытаюсь написать многопоточную программу и сталкиваюсь с некоторыми проблемами.

После того, как я запустил main.c , и я получаю

i: 0
новый поток 0
новый поток 1
i: 1
i: 1

 //main.c
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
void* routine(void* arg)
{
    int id = (intptr_t) arg;
    printf("new thread %dn", id);
    pthread_exit((void*)(intptr_t) id);
}
int main()
{
    pthread_t t[2];
    int i;
    for(i=0; i<2; i  )
    {
        int ret = pthread_create (amp;t[i], NULL, amp;routine,  (void *)(intptr_t) i);
        if(ret != 0) {
            printf("Error: pthread_create() failedn");
            return -1;
        }
    }
    int id;
    /////////here
    for(i=0; i<2; i  )
    {
        printf("i: %dn",i);
        pthread_join(t[i], (void **)amp;id);
    }
    /////////here
    pthread_exit(NULL);
}
  

Мои проблемы

  • Почему последний цикл выполняется трижды?
  • Если я дважды изменяю pthread_t t[2] pthread_t t и создаю, можно ли дважды вызвать pthread_join ?

Спасибо, что уделили время чтению моего вопроса.

Комментарии:

1. ideone.com/MTWpZS

2. Что касается второго вопроса: Нет. Второй вызов pthread_create перезапишет pthread_t переменную.

3. @JoachimPileborg Я понял!! Спасибо @GillBates Версия моего компилятора gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4 , которая не работает правильно. Это проблема в зависимости от случая?

4. » это выполняется неправильно». в основном это никогда не ошибка в компиляторе.

5. @GillBates: Просто не повезло, похоже, что это сработало.

Ответ №1:

Сначала добавьте еще несколько отладочных журналов:

 int id;
for(i=0; i<2; i  )
{
    printf("i: %dn",i);
    pthread_join(t[i], (void **)amp;id);
    printf("id[%d]: %dn", i, id);
}
  

Повторно запустите и запомните результат.

Затем измените его, чтобы он выглядел следующим образом

 int id;
for(i=0; i<2; i  )
{
    void * pv;   
    printf("i: %dn",i);
    pthread_join(t[i], amp;pv); /* Add error checking here! */
    id = (intptr_t) pv;
    printf("id: %dn", id);
}
  

Повторно запустите и сравните с предыдущей версией.


Как правило,:

Если вы сталкиваетесь с кажущейся необходимостью приведения в C (не C ), всегда подумайте дважды, так как есть только очень, очень, очень редкие случаи, когда приведение в C необходимо, а не просто скрывает ошибку программирования, отключая компилятор.

Комментарии:

1. Я все еще думаю, что это немного странно при i изменении на 0 после вызова pthread_join в моем случае. Я не переходил i к этой функции. Но в любом случае, спасибо за ваш ответ и предложения.

2. @ShawnHuang: pthread_join() ожидает, что a void** , адрес указателя, он отменит ссылку на него, чтобы стать a void* , а затем присваивает этому void* значению указателя, которое, вероятно, равно 8 байтам, память, на которую ссылается то, что вы передали, является an int , ее ширина составляет всего 4 байта. Таким образом, некоторые другие 4 байта перезаписываются. Эти 4 байта, скорее всего, принадлежат i .

3. Я никогда не учитывал этот побочный эффект при кастинге. Еще раз спасибо за вашу помощь.