如何创建未定义数量的线程并在窗口c上使用WaitForMultipleObjects()

问题描述:

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的一部分,如果可以的话,你应该尽量避免它。如果您可以设计以便不必等待线程完成,那么您将有更简单的多线程编程时间并避免很多痛苦。任何依靠计算线程数量的设计都是一样的 - 设计无所谓,并避免麻烦。 –

我已经看到,可以使用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