Попытка реализовать состояние гонки с помощью pthread

Я пытаюсь настроить состояние гонки, чтобы увидеть, как это происходит, чтобы получить понимание. Я написал код ниже. Это компилируется без каких-либо проблем, но когда я запускаю его, он не печатает счетчик при каждом запуске. Если запустить его дважды или трижды, то печатается счет. Правильно ли я понимаю, что в этом коде не обязательно, чтобы состояние гонки действительно имело место. (если это правильно, то я не уверен, как это происходит, поскольку граничных условий нет!). Может ли кто-нибудь дать мне некоторое представление, если мое понимание неверно или код?

Спасибо.

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

void *banking(void *);

int main(){
   int accounts[2]={0,0};
   pthread_t tid1,tid2;

     if(pthread_create(&tid1,NULL,banking,(void *)accounts))
     {
         perror("pthread_create");
          return 1;
     }


     if(pthread_create(&tid2,NULL,banking,(void *)accounts))
     {
          perror("pthread_create");
           return 1;
     }
     pthread_join(tid1, NULL);
     pthread_join(tid2, NULL);//program now goes into infinite loop.
    return 0;
    }

   void *banking(void * accounts){
        int *ptr=accounts;
        int count=0;
         do{
           int temp1=ptr[0];
           int temp2=ptr[1];
           int amount=rand();
             ptr[0]=temp1-amount;
             ptr[1]=temp2+amount;
              //printf("%d \n %d\n",ptr[0],ptr[1]);
           count++;
            }while((ptr[0]+ptr[1])==0);
         printf("%d\n",count);
            //return NULL;
           exit(0);
           }

Я пытался реализовать pthread_exit(NULL) для достижения логики, при которой поток завершался бы после завершения цикла do-while, но, насколько я понимаю, другой запущенный поток не остановится таким образом, из-за чего программы переходят в бесконечный петля. Я понял, что exit() из любого потока завершает процесс и включил exit(0) . Код отлично работает для некоторых значений, но случайным образом генерирует два разных значения «счетчика». Это происходит раз в 10-12 попыток. Пожалуйста, предложите, целесообразно ли использование выхода в многопотоковой функции и в какой ситуации у меня будет два разных значения count.


person f-z-N    schedule 19.09.2011    source источник
comment
У вас есть ошибка копирования и вставки во втором вызове pthread_create - вы, вероятно, хотите tid2 для первого параметра. Обратите внимание, что если бы вы скомпилировали с помощью gcc -Wall, вы бы получили предупреждение компилятора об этом и сэкономили время на отладку.   -  person Paul R    schedule 19.09.2011


Ответы (1)


1> сначала исправьте те ошибки, на которые указал "Paul R". потом

2> вам нужно использовать функцию pthread_join для успешного завершения обоих потоков.

здесь после создания обоих потоков основной процесс может быть завершен, поэтому в это время оба потока также завершаются, поэтому для преодоления этой формы используйте othread_join для обоих потоков в main ()

добавьте этот код в конец вашего main()

pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

Если вы все еще не понимаете основы состояния гонки, прочитайте часть ниже. который я скопировал из одного справочника

Предположим, что ваша программа имеет ряд заданий в очереди, которые обрабатываются несколькими параллельными потоками. Очередь заданий представлена ​​в виде связанного списка структурных объектов задания.

После того, как каждый поток завершает операцию, он проверяет очередь, чтобы узнать, доступно ли дополнительное задание. Если job_queue не равен нулю, поток удаляет заголовок связанного списка и устанавливает job_queue на следующее задание в списке. Функция потока, обрабатывающая задания в очереди, может выглядеть так, как показано в листинге 4.10. Листинг 4.10 ( job-queue1.c ) Функция потока для обработки заданий из очереди

#include <malloc.h>
struct job {
/* Link field for linked list.
struct job* next;
*/
/* Other fields describing work to be done... */
};
/* A linked list of pending jobs.
struct job* job_queue;
*/
/* Process queued jobs until the queue is empty.
void* thread_function (void* arg)
{
while (job_queue != NULL) {
/* Get the next available job. */
struct job* next_job = job_queue;
/* Remove this job from the list. */
job_queue = job_queue->next;
/* Carry out the work. */
process_job (next_job);
/* Clean up. */
free (next_job);
}
return NULL;
}
*/
4.4
Synchronization and Critical Sections

Теперь предположим, что два потока завершили задание примерно в одно и то же время, но в очереди осталось только одно задание. Первый поток проверяет, имеет ли значение job_queue значение null; обнаружив, что это не так, поток входит в цикл и сохраняет указатель на объект задания в next_job. В этот момент Linux прерывает первый поток и планирует второй. Второй поток также проверяет job_queue и, обнаружив, что он не равен нулю, также назначает тот же указатель задания для next_job. По неудачному стечению обстоятельств теперь у нас есть два потока, выполняющих одно и то же задание.

Что еще хуже, один поток отключит объект задания от очереди, оставив job_queue содержащим null. Когда другой поток оценивает job_queue->next, это приведет к ошибке сегментации.

Это пример состояния гонки. В «счастливых» обстоятельствах это конкретное расписание двух потоков может никогда не произойти, и состояние гонки может никогда не проявиться. Только при других обстоятельствах, возможно, при работе на сильно загруженной системе (или на новом многопроцессорном сервере важного клиента!) ошибка может проявляться.

Чтобы устранить условия гонки, вам нужен способ сделать операции атомарными. Атомарная операция неделима и непрерывна; как только операция начнется, она не будет приостановлена ​​или прервана до ее завершения, и в это время никакие другие операции выполняться не будут. В этом конкретном примере вы хотите проверить job_queue; если он не пустой, удалите первое задание, все как одну атомарную операцию.

person Jeegar Patel    schedule 19.09.2011
comment
Привет, мистер... мне нужно дождаться завершения потока? потому что я хочу, чтобы моя программа завершилась, как только возникнет состояние гонки. Поможет ли ожидание завершения потоков? - person f-z-N; 19.09.2011
comment
я думаю, что до того, как условие гонки будет завершено, используйте сон или thread_join, чтобы увидеть его эффект - person Jeegar Patel; 19.09.2011
comment
добавлено условие ожидания, программа выводит значение счетчика, но затем просто переходит в бесконечный цикл. Даже если я добавлю pthread_exit, произойдет то же самое. - person f-z-N; 19.09.2011
comment
тогда измени логику...!! я надеюсь, что вы можете сделать это ..! имейте в виду базовое понимание темы и делайте то, что вам понравится. - person Jeegar Patel; 19.09.2011
comment
Спасибо за руководство, мистер 32. У меня возникли еще некоторые сомнения, редактируя свой пост. - person f-z-N; 19.09.2011