2013-02-10 81 views
0

我試圖掌握多線程編程的概念,我覺得我做的很好,但後來我發現下面的代碼簡單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 */ 
} 

據我瞭解,變量client,本地的while循環,在完全相同的地址在每次循環分配。因此,當第一個客戶端被接受時,線程接收到&client,並且當第二個客戶端被接受時,client的值被新的數據套接字覆蓋,並且這可能在已經運行的線程中產生副作用第一個客戶。

五合一功能Child,這是服務線程的代碼,我可以看到參數被複制到一個局部變量:

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

,可能筆者認爲這個副本讓他以後篡改主要client變量,但恕我直言,這可能會導致競爭條件。如果第二個客戶端在第一個線程複製此變量時到達,則複製的值可能會損壞。

我對不對?

回答

1

是的,你是對的。有兩個明顯的方式來解決這個問題:

  1. 通行證client到線程,而不是&client

  2. 在堆上分配一個新的整數並將其地址傳遞給該線程,並讓線程在完成時釋放它。

+0

除此之外,'accept()'可能會失敗。在這種情況下'client'不會被覆蓋。 – 2013-11-23 15:38:43

1

是的,你是對的。

你可以證明你是對的int client = *(int*)arg;前添加一個長sleep,並連接到服務器的兩倍,而第一個客戶端線程。