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?

Answers


There are a few things that are very wrong with your usage of pthreads.

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.
  • We're passing &threadPtr[k] (of type pthread_t *), not &threadPtr (of type 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(). The pthread_create prototype is as follow:

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:

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):

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):

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.

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.

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.

Plus, the latter function must return a pointer to void and not just void that can produce a big mess with the stack.

First, use an array of connection fds

int connfd[MAXCON];

then save the connfd in

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


Need Your Help

How to access dispose method from fields that are in auto implemented properties

c# .net memory .net-4.0

Why is it that I can access the dispose method inside the Bmw getter setter method but not in the dispose() method?

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.