2013-01-23 42 views
0

以下循環位於程序主內部。它接受傳入的連接,並且有一個線程可以處理它。線程結束,結束整個程序?

問題是,只要任何線程終止,它就會終止整個程序。代碼如下:

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

} 

爲什麼這樣做?

+1

你確定了方法中的代碼執行嗎?我從來沒有見過非''void *'線程方法 –

+0

是的,線程就像一個魅力,只是主程序結束。出於好奇,你提到的標準約定是什麼? –

+1

創建線程後你在做什麼? – imreal

回答

4

有幾件事情這對你的pthreads的使用是非常錯誤的。

首先,我覺得你的意思是這樣的:

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

注意以下幾點:

  • 我們存儲stpthread_create()返回值和處理其錯誤情況。
  • 我們正在通過&threadPtr[k](類型pthread_t *),而不是&threadPtr(類型pthread_t **)。 這可能是您問題的原因。

但我有你的代碼的主要問題之一,是你通過傳遞readWriteToClientpthread_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,強調我的):

對於兩個有趣的ction類型兼容,都應指定兼容的返回類型。此外,參數類型列表(如果兩者都存在)應在參數號 和使用省略號終結符中一致; 對應參數應具有 兼容類型。 [...]

的函數指針被隱式轉換,你的功能反正叫,但是這是違法的,按照標準(C11,6.3.2.3/8,重點煤礦):

指向一種類型的函數的指針可以被轉換爲指向另一種類型的函數的指針並返回;結果應該比較 等於原始指針。 如果使用轉換的指針調用 函數,該函數的類型與引用類型不兼容,則 行爲未定義

由於您調用了未定義的行爲,因此在您執行操作後,不會告知代碼的行爲。

此外,請記住,將int轉換爲void *,並且不保證在沒有信息丟失(它是實現定義的)的情況下發生,因此請小心。

您的代碼中還有其他一些錯誤,如果您在啓用警告的情況下編譯,您應該看到總是

-1

我敢打賭,你的編譯器是yelding一些警告有關兼容的指針類型....

我的建議是在編譯階段修復每一個警告

如果這樣做了,你會注意到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); 

分配給本地變量,讓我知道,如果它的工作原理

+0

爲什麼不'int connfd =(int)inputconnfd;'? –

+0

,因爲根據我的固定版本,inputconnfd現在是一個指向void –

+1

-1的指針,用於提供錯誤和危險的建議。 ''pthread_create(threadPtr,NULL,readWriteToClient,(void *)&connfd);'是**無效**(如果是的話,轉換爲'(void *)'是不必要的和冗餘的)除非添加強同步以確保新線程在更改或超出範圍之前讀取該值。在大多數情況下,按值傳遞'connfd'是可取的,但它需要轉換爲'(void *)'。 –