[C] Multithread Server

Hi all,i'm new on this forum, excuse me for my english.

I have wrote a server that accept connection from multiple client with the fork,but every client had to insert data in a linear list.

The problem is that every client insert data in an own copy of the linear list and this is caused by the fork.

So i have to convert my server in a multithread server but i have no idea where to start.

Anyone has an example of a multithread server??

You are saying that you want to convert your server into Multithread server.
But you are spawning processes using fork() :slight_smile:

There are 2 steps
1) Replace fork call with thread creation
2) Initialize the list globally.

You have to synchronize between threads/processes in order to update the List.

--siva.

Hi,if i inizialize the list globally,can i resolve my problem?

I read something about the thread creation but i have to create a function and insert all the code of the server into it,is this correct?

There might be synchronization issues also, between threads in handling the list.
Also it is tedious to handle pointers with threads.
I would suggest to do a rough work/paper work before implementation if you are new to this.

i was thinking about the semaphore or something like that.

Don't you have an example of a multithreaded server?

Non-trivial with a process oriented paradigm. Making the list global won't help except
to save memory in the child.
There is a little pipe synchronization thing I wrote as an exercise as a while ago.
You may like it. :slight_smile: It's chuckle worthy.

#include "dlist.h"
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#include <time.h>


#define MAXTIMES 300

long dlist_count;

struct _encap_ {
int timer;
};

void *interrupt_hup(void *val) {
struct _encap_ p;
time_t now, then;                 
                                                               
                               pthread_detach(pthread_self());
                               memcpy(&p,val,sizeof(p));
                               printf("Interval set at %d\nThread id %d waiting till %d -- now = %d\n",p.timer,pthread_self(),time(NULL) + p.timer,time(NULL));
                               then = now = time(NULL);
                               while ((then = time(NULL)) < (now + p.timer)) {sleep(1);}
                               kill(getpid(),SIGHUP);
                               pthread_exit(NULL);
}
                                       
void walk_dlist(DLIST * h)
{
    int x = 0;
    while (h != NULL) {
	printf("Node %d at %p with prv = %p, nxt = %p and data = %p\n", x,
	       h, h->prv, h->nxt, h->data);
	x++;
	h = h->nxt;
    }
}

void bwalk_list(DLIST * h, int place)
{

    while (h != NULL) {
	printf("Node %d at %p with prv = %p, nxt = %p and data = %p\n",
	       place, h, h->prv, h->nxt, h->data);
	place--;
	h = h->prv;
    }
}

#define BSZ 256

/*idea create two separate dlists and keep them synched with pipes from parent to child
1) Allocate and populate pipe from stdin/file in  parent. Create pipe. Close read end.
2) Create signal handler in parent for sighup and on receipt update the child list.
3) sigsuspend event loop
***child***
1) fork() and  destroy the original dlist copy via dlist_destroy. Close write end of pipe.
2) Create list head and then event loop -- block on read from pipe and add to list with inbound data.
*/

DLIST *global;
int pip[2];

void handlehup(int sig) {
int v = 0;
char *dta;
              while (v < dlist_count) {
                     dta = (dlist_element(global,v))->data;
                     if (dta != NULL) {write(pip[1],dta,strlen(dta));}
                     v++;
              }
              printf("Finished update...\n");
}
                   
int do_child(void) {
int ret;
pid_t cn;
char buf[BSZ];
char *rec;
DLIST *synchrony;
sigset_t mask;
                    
                    if ( (cn = fork()) == 0) {
                         sigemptyset(&mask);
                         sigprocmask(SIG_SETMASK,&mask,NULL);
                         
                         close(pip[1]);
                         dlist_destroy(global,free);
                         synchrony =  dlist_element_init(NULL);

                         bzero(buf,BSZ);
                         while ((ret = read(pip[0],buf,BSZ)) > 0) {
                                  rec = malloc(BSZ);
                                  strcpy(rec,buf);
                                  dlist_append(synchrony,dlist_element_init(&rec));
                                  printf("Received new record in list at %p with %d elements = \n%s\n at pid %d\n",synchrony,dlist_count,rec,getpid());
                        }
                         printf("Exiting due to pipe read error in %d with return = %d\n",getpid(),ret);
                         perror("read()");
                         walk_dlist(synchrony);
                         if (dlist_count > 0) {dlist_destroy(synchrony,free);}
                         exit(1);
                     } else {
                         return cn;
                     }
}
                                 
int main(int argc, char **argv) {
int x;
FILE *pt;
char buf[BSZ];
char *rec;
pid_t chld;
struct _encap_ f;
sigset_t mask;
pthread_t interrupto;

                 if (argc != 2) {printf("Error: Please specify file for information in list.\n"); return -1;}
                 if ( (pt = fopen(argv[1],"r")) == NULL) {perror("fopen()"); return -1;}

                 signal(SIGHUP,handlehup);
                 global = dlist_element_init(NULL);
                 
                 srand(time(NULL));
                 bzero(buf,BSZ);
                 while (fgets(buf,BSZ,pt) != NULL) {
                       rec = malloc(BSZ);
                       strcpy(rec,buf);
                       dlist_append(global,dlist_element_init(&rec));
                 }
                 walk_dlist(global);
                 
                 
                 pipe(pip);

                 sigfillset(&mask);
                 sigdelset(&mask,SIGHUP);
                 sigdelset(&mask,SIGINT);
                 sigdelset(&mask,SIGCHLD);
 
                 printf("Starting child process at %d\n",chld = do_child());
                 close(pip[0]);

                 while (1) {f.timer = (1 + rand() % MAXTIMES); pthread_create(&interrupto,NULL,interrupt_hup,&f); sigsuspend(&mask); waitpid(0,NULL,WNOHANG);}
                 return 1;
}

The list adt and functionality is a coarse copy of that described in
'MasterIng Algorithms in C'. The pipe could be exchanged for socket,
named pipe, etc..

This is a good basic point about development scalability software network server.

The C10K problem

Best regards,

Iliyan Varshilov

Sure..we should always use fast non-blocking event mechanisms when possible and
this is a very good point. Threads and processes are not the answer.

For an exercise however, knowing how to do it is valuable in other systems areas besides
network servers.