这段代码中有竞争条件吗?

Posted

技术标签:

【中文标题】这段代码中有竞争条件吗?【英文标题】:There is a race condition in this code? 【发布时间】:2013-02-10 22:09:31 【问题描述】:

我正在尝试掌握多线程编程的概念,我认为我做得很好,但后来我找到了以下代码,用于一个简单的echo 服务器:

http://www.cs.utah.edu/~swalton/listings/sockets/programs/part2/chap7/echo-thread.c

我认为代码是错误的,因为它使用相同的main 局部变量来存储每个传入连接的数据套接字。特别关注main()这部分:

while (1)
   int client, addr_size = sizeof(addr);
    pthread_t child;

    client = accept(sd, (struct sockaddr*)&addr, &addr_size);
    printf("Connected: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
    if ( pthread_create(&child, NULL, Child, &client) != 0 )
        perror("Thread creation");
    else
        pthread_detach(child);  /* disassociate from parent */

据我了解,while 循环的局部变量client 在循环的每次迭代中都分配在完全相同的地址。因此,当第一个客户端被接受时,线程接收到&client,当第二个客户端被接受时,client 的值被新的数据套接字覆盖,这会对线程产生副作用,即已经在第一个客户端上运行。

观察函数Child的代码,也就是服务线程,可以看到参数被复制到了一个局部变量中:

void* Child(void* arg)
   char line[100];
    int bytes_read;
    int client = *(int *)arg;
    ...etc...

可能作者认为这个副本允许他稍后篡改主要的client 变量,但恕我直言,这可能会导致竞争条件。如果第二个客户端在第一个线程复制此变量时到达,则复制的值可能已损坏。

我说的对吗?

【问题讨论】:

【参考方案1】:

是的,你是对的。有两种明显的方法可以解决此问题:

    client 传递给线程,而不是&client

    在堆上分配一个新的整数并将其地址传递给线程,并在完成后让线程释放它。

【讨论】:

除此之外,accept() 可能会失败。在这种情况下,client 不会被覆盖。【参考方案2】:

是的,你是对的。

您可以通过在int client = *(int*)arg; 之前添加一个长的sleep 并在第一个客户端线程时连接到服务器两次来证明您是正确的。

【讨论】:

以上是关于这段代码中有竞争条件吗?的主要内容,如果未能解决你的问题,请参考以下文章

我们应该使用带有信号量的互斥量来进行正确的同步并防止竞争条件吗?

浅析条件竞争

你能告诉我这段代码在做啥吗?

Flutter:小部件状态:这段代码安全吗?

多线程和模板化单例竞争条件

pthread_once() 中的竞争条件?