尝试使用 pthread 实现竞争条件

发布于 2024-12-05 10:13:33 字数 1458 浏览 0 评论 0原文

我正在尝试设置竞争条件,看看它是如何获得理解的。我写了下面的代码。编译没有任何问题,但当我运行它时,它不会在每次运行时打印计数。如果运行两次或三次,则会打印计数。我的理解是否正确,在这段代码中,竞争条件实际上没有必要发生。 (如果这是正确的,那么我不确定这是如何退出的,因为没有边界条件!)。如果我的理解或代码不正确,有人可以告诉我一些想法吗?

谢谢。

#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 次尝试就会发生一次。请建议是否建议在线程函数中使用 exit 以及在什么情况下我会有两个差异计数值。

I am trying to set-up race condition to see how it happens to get an understanding. I wrote the code below. This compiles without any issue but when I run it, it does not print the count at every run. If is run it twice or thrice , then the count is printed. Is my understanding correct that in this code it is not necessary that race condition actually takes place.
( if this is correct,then I am not sure how this exits since there are no boundary condition!). Can some one give me some idea if my understanding is incorrect or the code?

Thanks.

#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);
           }

I was trying to implement pthread_exit(NULL) to achieve the logic where the thread would exit once it do-while loop is over but as per my understanding the other running thread will not stop this way,because of which the programs goes into an infinite loop. I realized that exit() from any thread terminates process and incorporated exit(0) . The code works fine for some values but at random generates two different 'count' values. This happens once in 10-12 tries. Please suggest if usage of exit in a threaded function is advisable and under what situation will I have two diff values of count.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

茶花眉 2024-12-12 10:13:33

1>首先纠正“Paul R”所指出的错误。那么

2>
您需要使用 pthread_join 函数来成功完成两个线程。

创建两个线程后,主进程可能会结束,因此那时两个线程也都结束了,因此要克服这个问题,请在 main 中的两个线程中使用 othread_join ( )

将此代码添加到 main() 的末尾

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

如果您仍然没有获得竞争条件的基础,请阅读下面的部分。这是我从一本参考书中复制的

假设您的程序有一系列排队作业,这些作业由多个作业处理
并发线程。作业队列由 struct job 的链表表示
对象。

每个线程完成一个操作后,它会检查队列以查看是否有额外的操作
有工作。如果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;寻找-
如果不是,线程进入循环并将指向作业对象的指针存储在
下一个工作。此时,Linux恰好中断了第一个线程并调度了
第二个。第二个线程也检查 job_queue 并发现它非空,也分配
指向 next_job 的相同作业指针。不幸的是,我们现在有两个
线程执行相同的作业。

更糟糕的是,一个线程将从队列中取消作业对象的链接,
让 job_queue 包含 null。当另一个线程评估 job_queue->next 时,
将导致分段错误。

这是竞争条件的示例。在“幸运”的情况下,这个特殊的
两个线程的调度可能永远不会发生,并且竞争条件可能永远不会发生
展示自己。只有在不同的情况下,也许在重度跑步时
加载的系统(或在重要客户的新多处理器服务器上!)可能会
错误会自行显现。

为了消除竞争条件,您需要一种使操作原子化的方法。一个原子
操作不可分割且不间断;一旦操作开始,就不会
暂停或中断直到完成,并且不会发生其他操作意味着-
尽管。在此特定示例中,您想要检查 job_queue;如果不为空的话
删除第一个作业,全部作为单个原子操作。

1> first correct that mistakes which "Paul R" has sauggested. then

2>
you need to use pthread_join function to get succesfully completion of both thread..

here after creating both thread main process may be get over so at that time both threads are also gets over so to over come form this use othread_join for both thread in main()

add this code to end of at your main()

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

if you still not getting the funda of race condition then read belows part. which i have copied from one refrence book

Suppose that your program has a series of queued jobs that are processed by several
concurrent threads.The queue of jobs is represented by a linked list of struct job
objects.

After each thread finishes an operation, it checks the queue to see if an additional
job is available. If job_queue is non-null, the thread removes the head of the linked list
and sets job_queue to the next job on the list.
The thread function that processes jobs in the queue might look like Listing 4.10.
Listing 4.10 ( job-queue1.c) Thread Function to Process Jobs from the Queue

#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

Now suppose that two threads happen to finish a job at about the same time, but only
one job remains in the queue.The first thread checks whether job_queue is null; find-
ing that it isn’t, the thread enters the loop and stores the pointer to the job object in
next_job. At this point, Linux happens to interrupt the first thread and schedules the
second.The second thread also checks job_queue and finding it non-null, also assigns
the same job pointer to next_job. By unfortunate coincidence, we now have two
threads executing the same job.

To make matters worse, one thread will unlink the job object from the queue,
leaving job_queue containing null.When the other thread evaluates job_queue->next,
a segmentation fault will result.

This is an example of a race condition. Under “lucky” circumstances, this particular
schedule of the two threads may never occur, and the race condition may never
exhibit itself. Only under different circumstances, perhaps when running on a heavily
loaded system (or on an important customer’s new multiprocessor server!) may the
bug exhibit itself.

To eliminate race conditions, you need a way to make operations atomic. An atomic
operation is indivisible and uninterruptible; once the operation starts, it will not be
paused or interrupted until it completes, and no other operation will take place mean-
while. In this particular example, you want to check job_queue; if it’s not empty,
remove the first job, all as a single atomic operation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文