简体   繁体   English

线程结束,结束整个程序?

[英]Thread ending, ends the entire program?

The following loop is inside the main of the program. 以下循环位于程序的内部。 It accepts an incoming connection, and has a thread do work with it. 它接受传入的连接,并有一个线程可以处理它。

The problem is, as soon as any thread terminates, it terminates the entire program. 问题是,一旦任何线程终止,它就会终止整个程序。 Here's the code: 这是代码:

#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#define BUFLEN 1500
#define MAXCON 30

char *returnTimeDate(int inputchoice);
void readWriteToClient(int inputconnfd);

int main(){

    int backlog = 10;

    int fd;
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1) {
        // Error: unable to create socket
    }

    struct sockaddr_in cliaddr;
    socklen_t cliaddrlen = sizeof(cliaddr);

    struct sockaddr_in addr;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(5001);

    if (bind(fd, (struct sockaddr *) &addr, (socklen_t) sizeof(addr)) == -1) {
        fprintf(stderr,"Bind Didn't Work\n");
    }

    if (listen(fd, backlog) == -1) {
        fprintf(stderr,"Listen Didn't Work\n");
    }

    pthread_t *threadsArray = (pthread_t *)calloc(MAXCON, sizeof(pthread_t));
    pthread_t *threadPtr = threadsArray;

    int k;
    for(k = 0; k < MAXCON; k++){
        fprintf(stderr,"Make %d\n",k);
        int connfd;
        connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
        if (connfd == -1) {
            fprintf(stderr,"Accept Didn't Work\n");
        }
        fprintf(stderr,"Waited\n",k);
        pthread_create( &threadPtr, NULL, readWriteToClient, (void *)connfd);
        threadPtr++;
    }

    pthread_t *threadPtrJoin = threadsArray;

    for(k = 0; k < MAXCON; k++){
        fprintf(stderr,"Join %d\n",k);
        pthread_join( *threadPtrJoin, NULL);
        threadPtrJoin++;
    }

/*  readWriteToClient(connfd);*/

    close(fd);

    return 0;

}

void readWriteToClient(int inputconnfd){

    int connfd = inputconnfd;

    while(1){

        char *dateString = "DATE\r\n";
        char *timeString = "TIME\r\n";
        char *endString = "end";

        char *bufferTime = returnTimeDate(0);
        char *bufferDate = returnTimeDate(1);

        ssize_t i;
        ssize_t rcount;
        char buf[BUFLEN];
        char *toReturn = (char *)malloc(BUFLEN*sizeof(char));
        rcount = read(connfd, buf, BUFLEN);
        if((strcmp (buf, dateString)) == 0){
            strcpy(toReturn, bufferDate);
        }
        if((strcmp (buf, timeString)) == 0){
            strcpy(toReturn, bufferTime);
        }
        if((strcmp (buf, endString)) == 0){
            goto outside;
        }
        if (rcount == -1) {
            // Error has occurred
            printf("Error: rcount -1");
        }

/*      fprintf(stderr,"I have received = %s\n",buf);*/

        if (write(connfd, toReturn, BUFLEN) == -1) {
            fprintf(stderr,"I didn't write = %s\n",buf);    
        }
    }

    outside: return;

}

char *returnTimeDate(int inputchoice){

    time_t timer;
    char *bufferTimee = (char *)malloc(25*sizeof(char));
    char *bufferDatee = (char *)malloc(25*sizeof(char));
    struct tm* tm_info;
    time(&timer);
    tm_info = localtime(&timer);
    strftime(bufferTimee, 25, "%H:%M:%S\n\0", tm_info);
    strftime(bufferDatee, 25, "%d:%m:%Y\n\0", tm_info);

    if(inputchoice == 0){
        return bufferTimee;
    }else{
        return bufferDatee;
    }

}

Why is it doing this? 为什么这样做呢?

There are a few things that are very wrong with your usage of pthreads. 使用pthread时有些事情是非常错误的。

First of all, I think you meant this: 首先,我认为您的意思是:

int st = pthread_create(&threadPtr[k], NULL, readWriteToClient, (void *)connfd);
if (st != 0) {
    /* handle error */
}

Note the following: 请注意以下几点:

  • We're storing the return value of pthread_create() in st and handling its error case. 我们将pthread_create()的返回值存储在st并处理其错误情况。
  • We're passing &threadPtr[k] (of type pthread_t * ), not &threadPtr (of type pthread_t ** ). 我们传递的是&threadPtr[k] (类型为pthread_t * ),而不是&threadPtr (类型为pthread_t ** )。 This was likely the cause of your issue. 这可能是造成您问题的原因。

But one of the main issues I have with your code, is that you are invoking undefined behavior by passing readWriteToClient to pthread_create() . 但是我的代码存在的主要问题之一是,您通过将readWriteToClient传递给pthread_create()来调用未定义的行为。 The pthread_create prototype is as follow: pthread_create原型如下:

int pthread_create(pthread_t *restrict,
                   const pthread_attr_t *restrict,
                   void *(*start_routine)(void*), 
                   void *restrict arg);

Even if you change &threadPtr to &threadPtr[k] , you'd be calling it as follow: 即使将&threadPtr更改为&threadPtr[k] ,您也可以按以下方式调用它:

int pthread_create(pthread_t *restrict,
                   const pthread_attr_t *restrict,
                   void (*start_routine)(int),      // oops!
                   void *restrict arg);

So, the pthread_create() accepts a pointer to a function of one type, but you're passing it a pointer to a function of another type (C11, 6.7.6.3/15, emphasis mine): 因此, pthread_create()接受指向一种类型的函数的指针,但是您要向其传递指向另一种类型的函数的指针(C11,6.7.6.3 / 15,重点是我的):

For two function types to be compatible, both shall specify compatible return types . 为了使两个函数类型兼容,两者都应指定兼容的返回类型 Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; 此外,参数类型列表(如果同时存在)应在参数数量和省略号终止符的使用上达成共识; corresponding parameters shall have compatible types . 相应的参数应该具有兼容的类型 [...] [...]

The pointer to the function is implicitly converted, and your function is called anyway, but this is illegal, as per the standard (C11, 6.3.2.3/8, emphasis mine): 指向该函数的指针被隐式转换,并且无论如何都会调用您的函数,但这按照标准(C11,6.3.2.3 / 8,强调我的)是非法的:

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; 可以将指向一种类型的函数的指针转换为指向另一种类型的函数的指针,然后再次返回。 the result shall compare equal to the original pointer. 结果应等于原始指针。 If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined . 如果使用转换后的指针来调用类型与所引用类型不兼容的函数,则该行为是undefined

Since you are invoking undefined behavior, there's no telling how the code will behave after you do. 由于您正在调用未定义的行为,因此您无需知道代码在执行后的行为。

Also, keep in mind that converting an int to a void * and back is not guarantee to happen without loss of information (it's implementation-defined), so be careful with that. 另外,请记住,将int转换为void *并返回并不能保证不会丢失信息(这是实现定义的),因此请务必谨慎。

There are a few other errors in your code that you should see if you compile with warnings enabled, something you should always do. 如果在启用警告的情况下进行编译 ,您应该在代码中看到其他一些错误, 应该始终这样做。

I bet your compiler was yelding some warning about incompatible pointer type.... 我敢打赌,您的编译器对不兼容的指针类型发出了一些警告。

My suggestion is TO FIX EVERY WARNING during the compile phase. 我的建议是在编译阶段修正所有警告

If this was done, you'd notice that the parameter of the pthread function must be a pointer to void and not an int. 如果这样做,您会注意到pthread函数的参数必须是指向void的指针,而不是int。

Plus, the latter function must return a pointer to void and not just void that can produce a big mess with the stack. 另外,后一个函数必须返回一个指向void的指针,而不仅仅是返回可能导致堆栈混乱的void的指针。

First, use an array of connection fds 首先,使用连接fds的数组

int connfd[MAXCON];

then save the connfd in 然后将connfd保存在

connfd[k] = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);

then, change 然后,改变

pthread_create( threadPtr, NULL, readWriteToClient, connfd);

with

pthread_create( threadPtr, NULL, readWriteToClient, (void *) &connfd[k]);

and change 并改变

void readWriteToClient(int inputconnfd)

with

void *readWriteToClient(void *inputconnfd)

then assign it to the local variable with 然后将其分配给本地变量

int connfd = *((int *) inputconnfd);

let me know if it works 让我知道是否有效

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

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