Trying to implement race condition using pthread
我正在尝试设置比赛条件,以了解它是如何发生的。我写了下面的代码。这编译没有任何问题,但是当我运行它时,它不会在每次运行时打印计数。如果运行两次或三次,则打印计数。我的理解是否正确,在这段代码中,没有必要实际发生竞争条件。
(如果这是正确的,那么我不确定这是如何退出的,因为没有边界条件!)。如果我的理解不正确或代码,有人可以给我一些想法吗?
谢谢。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #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 \ %d\ ",ptr[0],ptr[1]); count++; }while((ptr[0]+ptr[1])==0); printf("%d\ ",count); //return NULL; exit(0); } |
我试图实现 pthread_exit(NULL) 以实现线程在 do-while 循环结束后退出的逻辑,但根据我的理解,其他正在运行的线程不会以这种方式停止,因为程序会这样运行进入无限循环。我意识到任何线程的 exit() 都会终止进程并合并 exit(0) 。该代码适用于某些值,但随机生成两个不同的 \\'count\\' 值。这在 10-12 次尝试中发生一次。请建议是否建议在线程函数中使用 exit 以及在什么情况下我会有两个差异计数值。
1> 首先纠正"Paul R"提出的错误。然后
2>
您需要使用 pthread_join 函数来成功完成两个线程..
在这里创建两个线程后,主进程可能会结束,所以那时两个线程也都结束了,所以在 main() 中为两个线程使用 othread_join
将此代码添加到 main()
的末尾
1 2 | pthread_join(tid1, NULL); pthread_join(tid2, NULL); |
如果您仍然没有了解比赛条件的基础,请阅读以下部分。我从一本参考书中复制的
假设您的程序有一系列排队的作业,由几个
并发线程。作业队列由结构作业的链表表示
对象。
每个线程完成一个操作后,它会检查队列以查看是否有额外的
有工作。如果job_queue不为null,则线程移除链表的头部
并将 job_queue 设置为列表中的下一个作业。
处理队列中作业的线程函数可能类似于代码清单 4.10。
清单 4.10 (job-queue1.c) 处理队列中的作业的线程函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #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 是否为空;寻找-
知道它不是,线程进入循环并将指向作业对象的指针存储在
下一个工作。此时,Linux恰好中断了第一个线程并调度了
第二个。第二个线程还检查 job_queue 并发现它非空,也分配
指向下一个作业的相同作业指针。不幸的巧合,我们现在有两个
执行相同作业的线程。
更糟糕的是,一个线程会从队列中取消作业对象的链接,
留下job_queue包含null。当其他线程评估job_queue->next时,
将导致分段错误。
这是一个竞争条件的例子。在一个€?luckya€?情况下,这种特殊的
两个线程的调度可能永远不会发生,并且竞态条件可能永远不会发生
展示自己。只有在不同的情况下,也许是在重载上运行时
加载系统(或在重要客户的新多处理器服务器上!)可能
错误展示自己。
要消除竞争条件,您需要一种使操作原子化的方法。一个原子
操作是不可分割和不间断的;一旦操作开始,就不会
暂停或中断,直到完成,并且不会发生其他操作意味着-
尽管。在此特定示例中,您要检查 job_queue;如果它不是空的,
删除第一个作业,全部作为单个原子操作。