Барьеры для синхронизации потоков - PullRequest
1 голос
/ 24 сентября 2010

Я создаю n потоков и затем запускаю исполнение после разрушения барьера.

В глобальном пространстве данных:

int bkdown = 0;

В основном ():

pthread_barrier_init(&bar,NULL,n);

for(i=0;i<n;i++)
{
pthread_create(&threadIdArray[i],NULL,runner,NULL);
if(i==n-2)printf("breakdown imminent!\n");
if(i==n-1)printf("breakdown already occurred!\n");
}

В функции нитенаправителя:

void *runner(void *param)
{
 pthread_barrier_wait(&bar);

 if(bkdown==0){bkdown=1;printf("barrier broken down!\n");}

        ...

 pthread_exit(NULL);
}

Ожидаемый заказ:

breakdown imminent!
barrier broken down!
breakdown already occurred!

Фактический заказ: (проверено многократно)

breakdown imminent!
breakdown already occurred!
barrier broken down!!

Может ли кто-нибудь объяснить, почему я не получаю сообщение "broken down" до сообщения "already occurred"?

Ответы [ 4 ]

3 голосов
/ 24 сентября 2010

Порядок выполнения потоков зависит от операционной системы. Тот факт, что вы запускаете поток, не означает, что ОС запустит его немедленно.

Если вы действительно хотите контролировать порядок, в котором выполняются потоки, вы должны поместить туда какую-то синхронизацию (с мьютексами или условными переменными.)

2 голосов
/ 24 сентября 2010
for(i=0;i<n;i++)
{
pthread_create(&threadIdArray[i],NULL,runner,NULL);
if(i==n-2)printf("breakdown imminent!\n");
if(i==n-1)printf("breakdown already occurred!\n");
}

Ничто не останавливает выполнение этого цикла до i == n-1. pthread_create () просто запускает поток для запуска. Он не ждет, чтобы это началось или закончилось. Таким образом, вы попали в зависимость от планировщика, который может решить продолжить выполнение вашего цикла или переключиться на один из вновь созданных потоков (или выполнить оба в системе SMP).

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

1 голос
/ 25 сентября 2010

В дополнение к ответам nos и Starkey вы должны принять во внимание, что в вашем коде есть другая сериализация, которой часто пренебрегают: вы выполняете IO для той же переменной FILE, а именно stdin.

Доступ к этой переменной внутренне мьютексирован, и порядок, в котором ваши n+1 потоки (включая ваш вызывающий поток) получают доступ к этому мьютексу, определяется реализацией, в вашем случае это в основном случайное.

Таким образом, порядок, в котором вы получаете вывод printf, - это порядок, в котором ваши нити проходят через эти червоточины.

0 голосов
/ 20 мая 2011

Вы можете получить ожидаемый заказ одним из двух способов

  • Создать каждый поток с более высоким приоритетом, чем основной поток.Это гарантирует, что новый поток запустится сразу после создания и будет ждать на барьере.
  • Переместите печать «неизбежно! \ N» перед pthread_create () и вызовите вызов sched_yield () после каждого pthread_create ().Это запланирует выполнение вновь созданного потока.
...