2017-09-03 57 views
0

我已經使用pthread庫在c中編寫了多客戶端服務器。當每個客戶端嘗試連接到服務器時,每個客戶端都作爲單獨的線程運行,並使用handle_client函數處理每個客戶端。爲什麼線程函數的參數應該在堆中?

我想知道爲什麼我需要在堆中聲明connfd作爲變量?如果它被聲明爲局部變量可能會發生什麼問題?

這是代碼,以使每個線程(在main()函數)

int* connfd; 
pthread_t thread_id; 
int client_sock 

while (1) 
{ 
    connfd = malloc(sizeof(int)); 
    *connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); 

    if(pthread_create(&thread_id , NULL , handle_client , (void*)&client_sock) < 0) 
    { 
     perror("could not create thread"); 
     return 1; 
    } 
} 

這是我hadle_client功能。

void* handle_client(void* connfd) 
{ 
    /* read a string sent by the client, 
    * print it and then send the string 
    * "Hello from the server" to the client*/ 

    int sock = *(int*)connfd; 
    int read_size; 
    char *message , client_message[2000]; 

    //Send some messages to the client 
    message = "Hello from the server\n"; 
    write(sock , message , strlen(message)); 

    while((read_size = recv(sock , client_message , 2000 , 0)) > 0) 
    { 
     //end of string marker 
     client_message[read_size] = '\0'; 

     //Send the message back to client 
     puts(client_message); 

     //clear the message buffer 
     memset(client_message, 0, 2000); 
    } 

    if(read_size == 0) 
    { 
     puts("Client disconnected"); 
     fflush(stdout); 
    } 

    else if(read_size == -1) 
    { 
     perror("recv failed"); 
    } 

    free(connfd); 
    return NULL; 
} 
+0

注意到在你的代碼中,你傳遞一個指向未初始化的自動'client_sock'的指針;那看起來不正確 –

回答

1

對於代碼才能正常工作,必須確保:

  • 只要它需要存在由handle_client線程包含連接句柄(在你的代碼,*connfd)變量;
  • 其值不會被while循環的後續迭代覆蓋。

用堆變量來實現這一點更容易,就像您在代碼中所做的一樣。

通常,將本地(自動,基於堆棧的)變量的地址傳遞給線程函數並不一定是錯誤的。它只需要比使用基於堆的變量更多的關注。

+0

'一般來說,傳遞本地地址不一定是錯誤的 - 總的來說不是錯誤的,但是在大多數常見的實現中有時不是。正確的方法是將線程之間使用的數據與線程本身使用的數據分開。 –

1

有問題

  • 它可能是它在線程中使用之前的變量的生命週期結束。它的生命週期之後訪問對象有未定義行爲
  • C11無行爲,在訪問其他線程局部變量指定之前。作爲行爲沒有被定義,它是隱式未定義
  • C11表示從另一個線程訪問的自動變量的行爲是實現定義

    其標識符被聲明沒有一個目的鏈接並且沒有存儲類說明符靜態具有自動存儲持續時間,就像一些複合文字一樣。嘗試與從除了與該對象相關聯的一個其它的螺紋自動存儲持續時間間接地訪問對象的結果是實現定義的。

    你看了編譯器手冊了嗎?

    GCC說:

    這種訪問被支持,但具有用於並行訪問作爲用於並行訪問的任何對象同步的相同要求。

  • 即使支持訪問,也有可能發生數據競爭,包括編譯器決定不再需要此值。這些點的

適用於動態分配和其他線程已啓動後不能修改的對象。

1

如果使用局部變量,它將在主線程的堆棧中初始化。這將是安全的將該變量的地址傳遞給相應的線程,因爲主線程的棧變量生存期顯然會足夠長。 但這樣做的問題是你每次更新fd值while(1)在同一局部變量,這將使每個線程使用,導致未定義的行爲。

您必須爲每個線程分配堆棧或堆棧中的新變量,因此每個線程都應該能夠正確讀取正確的fd值而不會有任何歧義。

相關問題