2017-09-25 48 views
-1

PS:我對線程很陌生。如何創建未定義數量的線程並在窗口c上使用WaitForMultipleObjects()

我有一個問題,我需要等待來自客戶端的連接請求(完全任意的次數),接受套接字上的連接,連接後創建工作線程。創建的線程然後創建一個char數組,在其上工作並需要將其傳遞給父進程。

我已經能夠創建在while循環的螺紋等

while ((new_socket = accept(srv_sock, (struct sockaddr *)&client, &c)) != INVALID_SOCKET) 
{ 
    puts("\nConnection accepted"); 
    _beginthreadex(0, 0, handle_client, &new_socket, 0, 0); 

} 

我已經看到,pthread_join()可用於從線程父進程(在UNIX中)傳遞數據。我的問題是,我如何將它整合到主流程的循環中。 我希望採用以下方法將導致客戶端和服務器之間每次只能建立一個以上的連接,這是不需要的。

while ((new_socket = accept(srv_sock, (struct sockaddr *)&client, &c)) != INVALID_SOCKET) 
    { 
     puts("\nConnection accepted"); 
     _beginthreadex(0, 0, handle_client, &new_socket, 0, 0); 
     pthread_join(thread_id,&my_array); 

    } 

編輯:我會很高興知道如果我想是不可能的或者有替代pthread_join().或其等價物的窗戶。

編輯:我知道pthread_join()是Unix的,並且已經讀了WaitForMultipleObjects()是它的等效窗口。無論如何,我仍然無法找出解決方案。

+0

在這樣的「窗口」的方法是,我想,等一個IOCP完成端口對於客戶端連接接受,(重疊的AcceptEx)以及來自客戶端線程的排隊消息(PostQueuedCompletionStatus)。或者,在一個不同的線程中運行Accept()循環,並在生產者 - 消費者隊列(可能是PostMessage,GetMessage)中將所有內容排隊到你的'主線程'(或任何將要管理它的任何東西)。 –

+0

TBH,'join()'在所有情況下都是PITA的一部分,如果可以的話,你應該儘量避免它。如果您可以設計以便不必等待線程完成,那麼您將有更簡單的多線程編程時間並避免很多痛苦。任何依靠計算線程數量的設計都是一樣的 - 設計無所謂,並避免麻煩。 –

回答

0

我已經看到,可以使用pthread_join()將數據從線程傳遞給父進程。

這不完全正確。你可以通過一個指針,當你退出一個線程,並使用pthread_join收集該指針。你必須自己實現所有的邏輯。 API不知道(或關心)指針是什麼。線程沒有父母和孩子,他們是兄弟姐妹。

實施例用於創建者和收割者:

  • 全球

    struct VarLengthArray { 
        size_t count; 
        MyElem data[1]; 
    }; 
    
  • 退出螺紋:

    // allocate the result 
    size_t count = ...; 
    VarLengthArray *retval = malloc(
        sizeof(VarLengthArray) + 
        sizeof(MyElem) * (count > 0 ? count - 1 : 0) 
    ); 
    
    // fill the result 
    retval->count = count; 
    for (size_t i = 0; i < retval->count; ++i) { 
        retval->data[i] = ...; 
    } 
    pthread_exit(retval); 
    
  • 收集線程:

    // collect the result 
    void *retval_; 
    if (pthread_join(thread_one_id, &retval_) != 0) { 
        // handle error 
    } 
    VarLengthArray *retval = retval_; 
    
    // use the result 
    for (size_t i = 0; i < retval->count; ++i) { 
        printf("retval->[%u] = %s\n", (unsigned) i, retval->data[i].string_value); 
    } 
    
    // deallocate the result 
    free(retval); 
    

使用條件變量和衆多創作者的完整的例子:

#include <limits.h> 
#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

typedef struct Datum { 
    struct Datum *next; 
    char some_data[32]; 
} Datum; 

typedef struct SharedData { 
    pthread_mutex_t mutex; 
    pthread_cond_t cond_empty; 
    unsigned seed; 
    Datum *head, *tail; 
    unsigned children_alive; 
} SharedData; 

static void *thread_logic(void *argv_); 

int main(int argc, char **argv) { 
    unsigned thread_count = 2; 
    if (argc > 1) { 
     if (sscanf(argv[1], " %u ", &thread_count) != 1) { 
      fprintf(stderr, "Usage: %s [thread_count]\n", argv[0]); 
      return 1; 
     } 
    } 

    // initialize shared data 
    SharedData shared_data; 
    pthread_mutex_init(&shared_data.mutex, NULL); 
    pthread_cond_init(&shared_data.cond_empty, NULL); 
    shared_data.seed = time(NULL); 
    shared_data.head = NULL; 
    shared_data.tail = NULL; 
    shared_data.children_alive = 0; 

    // start threads detached, so you don't have to call pthread_join 
    pthread_t *child_ids = malloc(sizeof(pthread_t) * thread_count); 
    pthread_attr_t attr; 
    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 

    // start the threads 
    pthread_mutex_lock(&shared_data.mutex); 
    for (unsigned i = 0; i < thread_count; ++i) { 
     if (pthread_create(&child_ids[i], &attr, thread_logic, &shared_data) != 0) { 
      perror("pthread_create"); 
     } else { 
      ++shared_data.children_alive; 
     } 
    } 
    pthread_mutex_unlock(&shared_data.mutex); 

    pthread_attr_destroy(&attr); 

    // loop until all threads are dead 
    while (shared_data.children_alive > 0) { 
     // a condition variable: wait until there is data you can read 
     pthread_mutex_lock(&shared_data.mutex); 
     while (shared_data.head == NULL) { 
      pthread_cond_wait(&shared_data.cond_empty, &shared_data.mutex); 
     } 

     // collect a first datum 
     Datum *datum = shared_data.head; 
     if (datum->next != NULL) { 
      shared_data.head = datum->next; 
     } else { 
      shared_data.head = shared_data.tail = NULL; 
     } 

     pthread_mutex_unlock(&shared_data.mutex); 

     // handle the data (outside of the mutex lock) 
     printf("Got data: %s\n", datum->some_data); 
     free(datum); 
    } 

    return 0; 
} 

static void *thread_logic(void *shared_data_) { 
    SharedData *shared_data = shared_data_; 
    while (1) { 
     pthread_mutex_lock(&shared_data->mutex); 

     // create some data 
     useconds_t timeout = (
      (((float) (unsigned) rand_r(&shared_data->seed))/UINT_MAX) * 
      1000000 
     ); 
     Datum *datum = malloc(sizeof(Datum)); 
     datum->next = NULL; 
     if (timeout < 1000000/25) { 
      --shared_data->children_alive; 
      snprintf(datum->some_data, sizeof(datum->some_data), "I'm done\n"); 
     } else { 
      snprintf(
       datum->some_data, sizeof(datum->some_data), 
       "Sleeping for %uus\n", timeout 
      ); 
     } 

     // append the datum 
     if (shared_data->head) { 
      shared_data->tail->next = datum; 
     } else { 
      shared_data->head = datum; 
      pthread_cond_signal(&shared_data->cond_empty); 
     } 
     shared_data->tail = datum; 

     pthread_mutex_unlock(&shared_data->mutex); 

     // most likely it takes some time to create the data 
     // do lengthly tasks outside of the mutex lock 
     if (timeout < 1000000/25) { 
      return NULL; 
     } else { 
      usleep(timeout); 
     } 
    } 
} 
+0

如何在循環中pthread_join()?我也不知道創建了多少個線程。 – George

+0

@George,我會更新我的答案,但這需要幾分鐘的時間。當我完成時我會平息你。 :) – kay

+0

@George,請參閱我的更新 – kay

相關問題