簡體   English   中英

如何在windows上的c中創建未定義數量的線程並使用WaitForMultipleObjects()

[英]how to create undefined number of threads and use WaitForMultipleObjects() in c on windows

PS:我對線程很陌生。

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

我已經能夠在 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(). 或它的窗口等效項。

編輯:我知道pthread_join()是針對 Unix 的,並且已經讀過WaitForMultipleObjects()是 Windows 的等效項。 無論如何,我仍然無法找到解決方案。

我已經看到 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);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM