简体   繁体   English

如何正确终止pthread?

[英]How to properly terminate a pthread?

I have a tcp echo server that creates a pthread for each client that connects to it. 我有一个TCP回显服务器,该服务器为连接到它的每个客户端创建一个pthread。 For each connection, I have a variable nbOfClients that increments. 对于每个连接,我都有一个递增的变量nbOfClients When a client closes its connection, I detect it and decrease the number of clients. 当客户端关闭其连接时,我会检测到该连接并减少客户端数量。 However the server keeps thinking that the client it alive and keeps on trying to read/write from the socket. 但是,服务器一直认为客户端还活着,并继续尝试从套接字读取/写入。 I guessed that it was because of the thread that created the client and I tries to kill the thread with pthread_cancel all to non avail. 我猜想那是由于创建客户端的线程pthread_cancel ,我试图使用pthread_cancel杀死该线程,但全部无效。 I want to kill the pthread associated to a certain client that closes its connection. 我想杀死与某个关闭其连接的客户端关联的pthread。 How can I go about it? 我该怎么办?

Here's my code : 这是我的代码:

static int nbOfClients = 0;

static  pthread_t tid;

int main (int argc, char *argv[]) {

    int bytes_to_read, arg, listen_sd, new_conn, sockfd, client_len, port;
    struct sockaddr_in server, client_addr;
    char *bp, buf[BUFLEN];
    ssize_t n;


    sockfd = 0;

    switch(argc) {
        case 1:
          port = SERVER_TCP_PORT;   // Use the default port
          break;
        case 2:
          port = atoi(argv[1]); // Get user specified port
          break;
        default:
          fprintf(stderr, "Usage: %s [port]\n", argv[0]);
          exit(1);
    }

    // Create a stream socket
    if ((listen_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        error("Cannot Create Socket!");

    // set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c
    arg = 1;
    if (setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1)
        error("setsockopt");

    // Bind an address to the socket
    bzero((char *)&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = htonl(INADDR_ANY); // Accept connections from any client

    if (bind(listen_sd, (struct sockaddr *)&server, sizeof(server)) == -1)
        error("bind error");

    listen(listen_sd, MAX_CONNECTIONS); ///put a define constant indicating the maximum number of clients #define NB_CLIENTS 3

    while (TRUE) {
        client_len = sizeof(client_addr);
        if ((new_conn = accept(listen_sd, (struct sockaddr *) &client_addr, (socklen_t *)&client_len)) == -1)
          error("accept error");

        if(new_conn > 0) {
            if(nbOfClients < MAX_CONNECTIONS) {
                printf("just here\n");
                printf(">> Initializing remote address: %s\n", inet_ntoa(client_addr.sin_addr));
                nbOfClients++;


                fclose(fp);

                printf("Connections to date: %u \n",nbOfClients);

                printf("make thread\n");
                pthread_create(&tid,NULL,&echo, (void *)new_conn);
                printf("had thread\n");
            }
            else {
                printf("connection limit reached\n");
                if(send(new_conn, "Server full!\n", 13, 0) == -1)
                    perror("send");
                close(new_conn);
            }
        }
    }

    return(0);
}

void * echo(void *arg) {
    char buf[BUFSIZE]; /* message buffer */
    int n, i = 0;

    bzero(buf, BUFSIZE);
    if(send((int)arg, "Welcome!!\n", 20, 0) == -1)
        perror("send");

    detect_closed_connection(arg);

    while(TRUE) {
        n = read((int)arg, buf, BUFSIZE);

        /**read: read input string from the client*/
        if(n < 0) {
            perror("error reading from socket");
        }

        printf("Server received from client, %d bytes: %s\n", n, buf);

        /**write: echo the input string in UPPERCASE back to the client*/

        int len = strlen(buf);
        for(i = 0; buf[i]; i++)
            buf[i] = toupper(buf[i]);

        n = write((int)arg, buf, len);
        if(n < 0) {
            error("ERROR writing to socket");
        }
    }
}

void detect_closed_connection(void * listenSocket) {
    struct pollfd pfd;
    pfd.fd = (int)listenSocket;
    pfd.events = POLLIN | POLLHUP | POLLRDNORM;
    pfd.revents = 0;
    while(pfd.revents == 0) {
        if(poll(&pfd, 1, 100) > 0) {
            // if result > 0, this means that there is either data available on the
            // socket, or the socket has been closed
            char buffer[32];
            if (recv((int)listenSocket, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
                // if recv returns zero, that means the connection has been closed:

                nbOfClients--;
                pthread_cancel(tid);

            }
        }
    }
}

Thanks. 谢谢。

You should check read() for returning 0 in the thread servering the client, as read() returns 0 in case the peer (client here) closed the connection. 您应该在为客户端提供服务的线程中检查read()是否返回0 ,因为如果对等方(此处的客户端)关闭了连接,则read()返回0

After this line 在这行之后

n = read((int)arg, buf, BUFSIZE);

add

if (0 == n)
{
  fprintf(stderr, "The client closed the connection.\n");
  break;
}

Just before the thread function leave you could add the statement to decrement the number of running threads. 就在线程函数离开之前,您可以添加该语句以减少正在运行的线程数。


Also be aware that nbOfClients is accessed concurently by all the "client"-threads as well as by the main thread, so accessing it shall be protected, for example by using a mutex. 还应注意,所有“客户端”线程以及主线程会同时访问nbOfClients ,因此应保护其访问,例如通过使用互斥锁。


There is another issues, as the call to strlen() on the buffer read expects the buffer to be 0 -terminate, which does not necessarily needs ot be the case, even if you sent 0 -terminated "strings". 还有另一个问题,因为对读取的缓冲区的strlen()的调用期望缓冲区为0终止,即使您发送了0终止的“字符串”,也不一定需要这种情况。 read() might very well return the "string" the client sent in more then one part. read()可能会返回客户端发送的“字符串”,而不是一部分。 So loop around read() until the 0 -terminator had been received. 因此,循环遍历read()直到接收到0终止符。


Do not make the thread end itself by calling pthread_cancel() , use pthread_exit() instead. 不要通过调用pthread_cancel()使线程本身结束,而应使用pthread_exit()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM