-1

PS:我对线程很陌生。

我有一个问题,我需要等待来自客户端的连接请求(完全任意次数),接受套接字上的连接,在连接后创建一个工作线程。创建的线程然后创建一个 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().或其 Windows 等价物。

编辑:我知道那pthread_join()是针对 Unix 的,并且已经读过WaitForMultipleObjects()它与 Windows 的等价物。无论如何,我仍然无法找到解决方案。

4

1 回答 1

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);
        }
    }
}
于 2017-09-25T08:52:20.870 回答