PDA

Visualizza la versione completa : [C] socket multi-thread


atomico
12-06-2010, 18:30
ciao a tutti, di solito su questo forum riesco a trovare sempre una risposta ai miei problemi.. speriamo che anche questa volta sia cos..

sto creando un server multi-thread.



while (1) {
if ( (fd2 = accept(fd1, (struct sockaddr*) &client_addr, &client_len)) <= 0 )
write(2, "Errore Accept\n", strlen("Errore Accept\n"));
else {
sprintf(buf, "FD2= %d\n", fd2);
write(2, buf, strlen(buf) );
if (pthread_create(&tid, NULL, client, &fd2))
write(2, "Errore pthread_create\n", strlen("Errore pthread_create\n"));
else {
sprintf(buf, "#Connessione: %d; Thread client: %u; Numero client connessi: %d#\n", fd2, (unsigned int)tid, CONT + 1);
write(1, buf, strlen(buf));


}
}
sleep(1);
}

close(fd1);
}


questa parte di codice quella che crea il thread nuovo...il problema che ho che il canale di comunicazione fd2 cambia di valore prima che il thread ne abbia preso il valore, per risolvere (artigianalmente) ho inserito quello sleep(1) che ovviamente bruttissimo da vedere.

come posso risolvere in maniera corretta?

oregon
12-06-2010, 18:36
Crea un semaforo dopo la accept e mettiti in attesa dopo la creazione del thread.

All'interno del nuovo thread, preleva il valore passato e segnala il semaforo.

atomico
12-06-2010, 18:45
mi faresti un esempio? ;)

grazie

oregon
12-06-2010, 18:49
Originariamente inviato da atomico
mi faresti un esempio? ;)


Ero praticamente sicuro che avresti fatto questa domanda ...

Hai provato a cercare/studiare/scrivere qualcosa tu? Sinceramente ho solo risposto per darti una strada da seguire, non per scrivere codice ...

atomico
12-06-2010, 19:37
ho fatto cos e sembra funzionare.. mi puoi dire almeno se corretto?



while (1) {

if ( (fd2 = accept(fd1, (struct sockaddr*) &client_addr, &client_len)) <= 0 )
write(2, "Errore Accept\n", strlen("Errore Accept\n"));
else {

sprintf(buf, "FD2= %d\n", fd2);
write(2, buf, strlen(buf) );
if (pthread_create(&tid, NULL, client, &fd2))
write(2, "Errore pthread_create\n", strlen("Errore pthread_create\n"));
else {
sprintf(buf, "#Connessione: %d; Thread client: %u; Numero client connessi: %d#\n", fd2, (unsigned int)tid, CONT + 1);
write(1, buf, strlen(buf));

pthread_cond_wait(&cond, &sem);

}
}


e nella funziona dopo l'acquisizione ho inserito

pthread_cond_signal(&cond);

MacApp
13-06-2010, 05:45
Originariamente inviato da atomico


if (pthread_create(&tid, NULL, client, &fd2))



stai passando l'indirizzo di una variabile (fd2) ad un thread (il che significa... guai) ;-)

io preferirei passargli un puntatore ad una struttura allocata dinamicamente con dentro tutti i parametri di cui necessitano ogni thread.

Se proprio vuoi passargli un intero, allora puoi barare, castando l'intero a void * e poi ri-castando (dentro il thread) il void * all'intero, ma... non portabile.

Eccoti un esempio (giusto per non fargli fare nulla, ad ogni thread faccio calcolare il numero di fibonacci in modo lento/ricorsivo):


/*
13 june 2010, MacApp

Simple example in C, using pthread

$ gcc --version
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) (dot 1)
$ gcc -Wall -Wextra -ansi -pedantic main.c

*/

#include <pthread.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

typedef unsigned long MyNatural;

typedef struct{
MyNatural fArg;
} SMyThreadArg;

static MyNatural IGSlowRecursiveFibonacci (const MyNatural theNatural){
MyNatural ret = 1;
assert (theNatural > 0);
if (theNatural > 2){
ret = IGSlowRecursiveFibonacci (theNatural - 1) + IGSlowRecursiveFibonacci (theNatural - 2);
}
return ret;
}

static void * MyThreadWorkerWithStruct (void * theThreadArg){
SMyThreadArg * aThreadArg = (SMyThreadArg *) theThreadArg;
assert (NULL != theThreadArg);
printf ("%s: IGRecursiveFibonacci (%ld) = %ld;\n", __func__, aThreadArg->fArg, IGSlowRecursiveFibonacci (aThreadArg->fArg));
free (theThreadArg);
return NULL;
}

static void * MyThreadWorkerWithDangerousCastToNatural (void * theThreadArg){
const MyNatural aNumber = (MyNatural) theThreadArg;
printf ("%s: IGRecursiveFibonacci (%ld) = %ld;\n", __func__, aNumber, IGSlowRecursiveFibonacci (aNumber));
return NULL;
}

#define MY_NUM_THREADS 40

int main (void){
pthread_t aContainerOfThreadId [2 * MY_NUM_THREADS];

unsigned long i;

assert (1 == IGSlowRecursiveFibonacci (1));
assert (1 == IGSlowRecursiveFibonacci (2));
assert (2 == IGSlowRecursiveFibonacci (3));
assert (3 == IGSlowRecursiveFibonacci (4));
assert (102334155 == IGSlowRecursiveFibonacci (40));

for (i = 0; i < MY_NUM_THREADS; ++i){
int aErr;
SMyThreadArg * aMyThreadArg = malloc (sizeof (SMyThreadArg));
assert (NULL != aMyThreadArg);
aMyThreadArg->fArg = i + 1;
aErr = pthread_create (&aContainerOfThreadId [i], NULL, MyThreadWorkerWithStruct, aMyThreadArg);
assert (0 == aErr);
}

for (i = 0; i < MY_NUM_THREADS; ++i){
const int aErr = pthread_create (&aContainerOfThreadId [i + MY_NUM_THREADS], NULL, MyThreadWorkerWithDangerousCastToNatural, (void *) (i + 1));
assert (0 == aErr);
}


printf ("waiting for threads;\n");

for (i = 0; i < sizeof (aContainerOfThreadId) / sizeof (aContainerOfThreadId [0]); ++i){
const int aErr = pthread_join (aContainerOfThreadId [i], NULL);
assert (0 == aErr);
}

printf ("bye bye...\n");
return 0;
}


;-)

xnavigator
15-06-2010, 13:48
puoi mettere i valori che devi passare in un array per ciascun thread che crei cosi non devi gestire i semafori :ciauz:

Loading