Попытка реализовать условие гонки, используя pthread - PullRequest
1 голос
/ 19 сентября 2011

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

Спасибо.

#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), чтобы получить логику, в которой поток завершит работу после завершения цикла, но, насколько я понимаю, другой работающий поток не остановится таким образом,из-за чего программы уходят в бесконечный цикл.Я понял, что выход () из любого потока завершает процесс и включил выход (0).Код отлично работает для некоторых значений, но случайным образом генерирует два разных значения 'count'.Это происходит один раз в 10-12 попыток.Пожалуйста, предложите, если использование выхода в многопоточной функции целесообразно, и в какой ситуации у меня будет два значения разности.

1 Ответ

2 голосов
/ 19 сентября 2011

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 нулевым;обнаружив, что это не так, поток входит в цикл и сохраняет указатель на объект задания в next_job.В этот момент в Linux происходит прерывание первого потока и планирование второго. Второй поток также проверяет задание job_queue и находит его ненулевым, а также назначает тот же указатель задания для next_job.К несчастью, теперь у нас есть два потока, выполняющих одно и то же задание.

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

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

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

...