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

跟風遠走 提交于 2019-12-25 18:36:28

问题


PS: I am very new to threads.

I have a problem where i need to wait for connection requests(completely arbitrary number of times) from clients, accept a connection on a socket, create a worker thread after connection. The created thread then creates a char array, works on it and needs to pass it to the parent process.

I have been able to create the threads in a while loop like

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

}

I have seen that pthread_join() can be used to pass data from thread to parent process(in unix). My question is, how can I integrate it into a loop in the main process. I expect the following approach will result in a situation where no more than one connection can be established between client and server at a time,which is not desired.

 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);

    }

EDIT: I would be happy to know if what I want is impossible or if there are alternatives to pthread_join(). or its windows equivalent.

EDIT: I know that pthread_join() is for Unix and have read that WaitForMultipleObjects() is its equivalent for windows. In any case I still haven't been able to figure out a solution.


回答1:


I have seen that pthread_join() can be used to pass data from thread to parent process.

That is not entirely correct. You can pass a pointer when you exit a thread, and collect that pointer using pthread_join. You have to implement all the logic yourself. The API does not know (or care) what the pointer is. Threads don't have parents and children, they are siblings.

Example for a creator and a reaper:

  • global

    struct VarLengthArray {
        size_t count;
        MyElem data[1];
    };
    
  • exiting thread:

    // 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);
    
  • collecting thread:

    // 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);
    

A full example using a condition variable and multiple creators:

#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);
        }
    }
}


来源:https://stackoverflow.com/questions/46400868/how-to-create-undefined-number-of-threads-and-use-waitformultipleobjects-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!