Pthread例程内部调用的通用函数将程序挂起

时间:2019-12-12 02:19:11

标签: c multithreading pthreads pthread-join

我正在用C做一个并发服务器以接受连接,它们将向我发送数据包中的字节,并且我需要在单独的线程中参与每个连接。我正在使用 Pthread_create()创建线程并在线程的例程内部,我正在调用一个函数来处理字节(数据包)的读取。

我注意到,第一个线程可以完美地完成所有工作,但是,第二个线程以及第二个线程之后的任何线程,程序只会挂起,并且永远不会做其他事情。

#include "csapp.h"

// Prototypes
void *thread(void *vargp);
void doProcess(int connfd, int portno);

struct threadArgu {
    int *connfdp;
    int portno;
};

/**
 * Thread-Based Concurrent Server
 */
int main(int argc, char *argv[]) {
    char* portno;
    int listenfd, *connfdp;
    socklen_t clientlen;
    struct sockaddr_storage clientaddr;

    if (argc < 2) {
        fprintf(stderr, "ERROR, no port provided\n");
        exit(1);
    }

    // The port number on which the server will listen for connections is passed in as an argument.
    portno = argv[1];

    listenfd = Open_listenfd(portno);

    // Makes the server capable of handling a number of simultaneous connections, each in its own thread.
    while (1) {
        // Connection
        clientlen = sizeof(struct sockaddr_storage);
        connfdp = Malloc(sizeof(int)); // Malloc of connected descriptor necessary to avoid deadly race
        *connfdp = Accept(listenfd, (SA *) &clientaddr, &clientlen);

        // Thread arguments
        args = calloc(1, sizeof(struct threadArgu));
        args->connfdp = connfdp;
        args->portno = atoi(portno);

        // Create thread
        pthread_t tid;
        Pthread_create(
                &tid, // The actual thread object that contains pthread id
                NULL, // Attributes to apply to this thread
                thread, // The function this thread executes
                args // Arguments to pass to thread function above
                );
    }
}

/**
 * Thread routine
 */
void *thread(void *vargp) {
    struct threadArgu *args = (struct threadArgu *) vargp;
    int connfdp = *((int *) args->connfdp);
    int portno = args->portno;
    printf("connfdp: %d\n", connfdp);
    printf("portno: %d\n", portno);

    Pthread_detach(pthread_self()); // Run thread in "detached mode"
    Free(args); // Free storage allocated
    doProcess(connfdp, portno); // Starts the work that this thread will do
    Close(connfdp);
    return NULL; // Peer thread terminates
}

/**
 * Starts the logic to read the messages and work with the bytes
 * @param connfd The connection file descriptor
 * @param portNo The port number of the connection
 */
void doProcess(int connfd, int portNo) {
    size_t n;
    char buf[MAXLINE];
    rio_t rio;

    Rio_readinitb(&rio, connfd);
    while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
       // Read the bytes and saves it
       Rio_readnb(&rio, tmpVariable->packet.data, numberOfBytes);
    }
}

请记住,每个连接都有自己的线程,自己的端口号,而我的函数doProcess()只是执行逻辑以一次从单个连接读取字节。这不是线程安全的!。

使用调试器工具,我可以看到线程#1此时位于(这在csapp.c库的函数内部)

void Pthread_join(pthread_t tid, void **thread_return) {
    int rc;
    if ((rc = pthread_join(tid, thread_return)) != 0) // <-- Is here
    posix_error(rc, "Pthread_join error");
}

并且线程#2此时是(这是我的功能)

void doProcess(int connfd, int portNo) {
    size_t n;
    char buf[MAXLINE];
    rio_t rio;

    Rio_readinitb(&rio, connfd);
    while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) { // <-- Is here
    }
}

我认为有多个线程正在调用我的函数并使我的函数逻辑发疯。

我的目标是一次参加一个连接,每个线程执行一次我的函数doProcess(),并避免其他线程在使用它时运行其他线程。

0 个答案:

没有答案