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

时间:2013-01-23 18:03:59

标签: c multithreading networking pthreads

以下循环位于程序主体内部。它接受传入连接,并且有一个线程可以使用它。

问题是,一旦任何线程终止,它就会终止整个程序。这是代码:

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

}

为什么要这样做?

2 个答案:

答案 0 :(得分:4)

使用pthreads时有一些问题非常严重。

首先,我认为你的意思是:

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

请注意以下事项:

  • 我们将pthread_create()的返回值存储在st中并处理其错误情况。
  • 我们正在传递&threadPtr[k]pthread_t *类型),而不是&threadPtr(类型pthread_t **)。 这可能是您问题的原因。

但是,我对您的代码的一个主要问题是,您通过将readWriteToClient传递给pthread_create()来调用未定义的行为。 pthread_create原型如下:

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

即使您将&threadPtr更改为&threadPtr[k],也可以按以下方式调用:

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

所以,pthread_create()接受一个指向一种类型函数的指针,但是你传递了一个指向另一种类型函数的指针(C11,6.7.6.3/15,强调我的):

  

要兼容两种功能类型,两者都应指定兼容的返回类型。   此外,参数类型列表(如果两者都存在)应在数量上一致   参数和省略号终止符的使用; 相应的参数应具备   兼容类型。 [...]

指向该函数的指针是隐式转换的,无论如何都要调用你的函数,但这是非法的,按照标准(C11,6.3.2.3/8,强调我的):

  

指向一种类型的函数的指针可以转换为指向a的指针   另一种类型的功能又回来了;结果应该比较   等于原始指针。 如果使用转换的指针进行调用   一个类型与引用类型不兼容的函数,   行为未定义

由于您正在调用未定义的行为,因此无法确定代码执行后的行为方式。

另外,请记住,将int转换为void *并返回并不能保证在不丢失信息的情况下(它是实现定义的),所以要小心。

如果在启用警告的情况下进行编译,您应该

>

答案 1 :(得分:-1)

我敢打赌你的编译器会对不兼容的指针类型发出警告....

我的建议是在编译阶段修复每个警告

如果这样做了,你会注意到pthread函数的参数必须是指向void而不是int的指针。

另外,后一个函数必须返回一个指向void的指针,而不仅仅是void,这会导致堆栈混乱。

首先,使用连接fds数组

int connfd[MAXCON];

然后将connfd保存在

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

然后,改变

pthread_create( threadPtr, NULL, readWriteToClient, connfd);

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

并更改

void readWriteToClient(int inputconnfd)

void *readWriteToClient(void *inputconnfd)

然后使用

将其分配给局部变量
int connfd = *((int *) inputconnfd);

让我知道它是否有效