PDA

View Full Version : Alcune domandine semplici sul C


Cimmo
16-10-2002, 10:59
1) Come faccio a specificare una variabile condivisa tra un processo e tutti i suoi figli futuri? Nel senso che il primo che modifica sta variabile, tale modifica deve essere visibile a tutti.

2) Visto che questo porta problemi di concorrenza: come si usano i semafori in C? C'e' (spero) una funzione che ti garantisce la mutuaesclusione nell'accesso a tale variabile rispetto a tutti i figli?

3) Esiste (qualcuno l'ha creata) una funzione che data una stringa ad ogni occorrenza di una sotto-stringa te la sostituisce con un'altra sotto-stringa? Del tipo: ogni "/" te lo sostituisce con un "?/"

grazie in anticipo

ciao
Cimmo

ilsensine
16-10-2002, 13:09
Parli di sistemi unix?

Cimmo
16-10-2002, 17:04
Si perche' cambia?

ilsensine
16-10-2002, 17:57
Certo.
Sotto i sistemi unix (in particolare linux) puoi ottenere memoria condivisa tramite shmget (v. pagina man); in sostanza, chiedi un'area di memoria di una certa dimensione, assegnandole una chiave. Qualsiasi altra applicazione che chiede memoria con la stessa chiave ottiene (permessi permettendo) la stessa area. Analogamente puoi ottenere un semaforo con semget (la pagina man indica anche le altre funzioni relative ai semafori); il principio della "chiave" unica è sempre lo stesso.
La shm va bene se devi spostare grandi quantità di dati o per accessi frequenti in lettura; altrimenti puoi usare delle valide alternative (come pipe, file mappati in tmpfs, socket ecc.).

Cimmo
16-10-2002, 18:05
Quindi shmget e semget...ok e la terza domanda ne sai qualcosa?
Altra cosa che centra piu' sulla Mandrake 9.0

a) Perche' non c'e' il man di niente (fork, strcmp, tutto manca)? E dire che durante l'installazione ho scelto tutte le categorie...che pacchetto mi manca?

b) E' sparito il pacchetto linuxlogo? Se si' lo posso ripescare da qualche parte?

grazie

ciao
Cimmo

ilsensine
16-10-2002, 20:23
a) Perche' non c'e' il man di niente (fork, strcmp, tutto manca)? E dire che durante l'installazione ho scelto tutte le categorie...che pacchetto mi manca?
Bella, questa.
Il pacchetto dovrebbe essere man-pages, però è assurdo che non sia installato...vabbè nella mdk 9 ne hanno combinate un pò di tutti i colori

b) E' sparito il pacchetto linuxlogo? Se si' lo posso ripescare da qualche parte?
Mai usato...

Cimmo
16-10-2002, 22:13
Originariamente inviato da ilsensine
[B]
Bella, questa.
Il pacchetto dovrebbe essere man-pages, però è assurdo che non sia installato...vabbè nella mdk 9 ne hanno combinate un pò di tutti i colori

Il pacchetto man-pages e' installato, cosi' come l'how-to e la documentazione. Pero' se faccio per esempio man shmget e man semget mi dice sempre no manual entry!
Se faccio man man invece funziona!

ilsensine
17-10-2002, 08:04
Puoi vedere se sotto /usr/share/man/man2 è presente shmget.2.bz2?

Cimmo
17-10-2002, 11:19
devo allocare della memoria condivisa tra diversi processi, per la precisione deve essere un stringa di MAXSIZE elementi, io l'ho fatto cosi':
int i=shmget(0,sizeof(char[MAXSIZE]),IPC_CREAT);
No; prova questo programma, eseguendolo più volte di seguito:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define __SHM_MAGIC__ 0x265170a1

#define fail(who) do { perror(who); exit(-1); } while(0)

int main() {
int id;
void *mem;

id = shmget(__SHM_MAGIC__, getpagesize(), IPC_CREAT|0660);
if(id<0) fail("shmget");
mem = shmat(id, NULL, 0);
if(!mem) fail("shmat");
printf("Segmento 0x%08x mappato su %p\n", id, mem);
printf("Primo intero: %d\n", (*(int*)mem)++);
printf("Nuovo valore: %d\n", *(int*)mem);
return 0;
}


Poi analogamente ho creato un semaforo cosi':
int i=semget(0,1,IPC_CREAT);
dopo come lo uso per la mutuaesclusione?
Devo darci un'occiata

ilsensine
17-10-2002, 12:00
Ahhh per sbaglio invece di inserire una risposta ho "modificato" il tuo messaggio :D
La vecchiaia...comunque è il caso di dire che...ti sei risposto da solo :D:D

Cimmo
17-10-2002, 12:05
Originariamente inviato da ilsensine
[B]Ahhh per sbaglio invece di inserire una risposta ho "modificato" il tuo messaggio :D
La vecchiaia...comunque è il caso di dire che...ti sei risposto da solo :D:D
Questi privilegi da moderatore...:D
non fa niente...adesso provero'...e spero di capirci qualcosa! Se ti viene qualcosa anche sui semafori ben venga...

ciao
Cimmo

ilsensine
17-10-2002, 12:38
I semafori sono un pò più complicati dei mutex; guarda man semop/semctl. Prova inoltre questo esempio:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#define __SEM_MAGIC__ 0x7688912a
#define fail(who) do { perror(who); exit(-1); } while(0)

union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};

int main() {
struct sembuf buf;
union semun cmd;
int id;
id = semget(__SEM_MAGIC__, 1, IPC_CREAT|0660);
if(id<0) fail("semget");
fprintf(stderr, "Creato il set di semafori 0x%08x\n", id);

/* Inizializza il semaforo, settando semval a 1 */
cmd.val = 1;
if(semctl(id, 0, SETVAL, cmd)<0) fail("semctl");

buf.sem_num = 0;
buf.sem_flg = SEM_UNDO; /* |IPC_NOWAIT per la forma non bloccante */

fork();

fprintf(stderr, "%d: Provo a bloccare il semaforo...\n", getpid());
buf.sem_op = -1;
if(semop(id, &buf, 1)<0) fail("semop"); /* Fallisce con EAGAIN se è specificato IPC_NOWAIT */

fprintf(stderr, "%d: Semaforo bloccato\n", getpid());
sleep(2); /* Aspetto un pò...*/

buf.sem_op = 1;
if(semop(id, &buf, 1)<0) fail("semop");
fprintf(stderr, "%d: Semaforo ripristinato\n", getpid());
return 0;
}

Cimmo
17-10-2002, 12:43
Alla fine a me serve un semaforo unico, nel senso che mi basterebbe un flag a cui accederci in mutua esclusione...non ho bisogno proprio di un semfaro che per definizione permette n accessi ad una risorsa condivisa (con 0<=n<=MAXRESOURCE)...quindi se esiste in C sotto Unix qualcosa di piu' semplice ancora meglio...illuminami di sapienza!

ilsensine
17-10-2002, 13:29
Ci sono i pthread_mutex, ma sono utilizzabili solo tra più thread. Non credo che mettendo uno di questi mutex nella memoria condivisa, e accedendoci da diversi processi, l'atomicità delle operazioni di lock sia assicurata.
Con i semafori comunque ottieni lo stesso risultato:

pthread_mutex_init <-> cmd.val=1; semctl(id, 0, SETVAL, cmd)
pthread_mutex_lock <-> buf.sem_op=-1; semop(id, &buf, 1)
pthread_mutex_unlock <-> buf.sem_op=1; semop(id, &buf, 1)

Cimmo
21-10-2002, 10:49
Per ora sto provando la shared memory, il problema e' che io ho bisogno di una stringa e lui mi da' un puntatore ad un'area di memoria che puo' essere qualsiasi cosa mi sembra aver capito (la dimensione di questa area pero' mi e' sconosciuta).
Io prima avevo una stringa statica:
char str[100];

se volevo scrivere nella 5 posizione facevo:

strncpy(&str[4],token,strlen(token));

adesso con un puntatore ad una stringa come cavolo faccio a ricavare l'indirizzo della posizione dalla quale partire a copiare l'altra sottostringa?

ilsensine
21-10-2002, 10:59
Devi copiare l'intera stringa nella shm, in quanto un processo non può accedere alla memoria di un altro processo. Tutte le gestioni sulle dimensioni ecc. le devi fare manualmente.
(la dimensione di questa area pero' mi e' sconosciuta)
La dimensione è un multiplo di getpagesize() bytes (sugli x86 vale 4096 byte).
E' memoria grezza, come quella allocata con malloc.

Cimmo
21-10-2002, 11:11
Originariamente inviato da ilsensine
[B]Devi copiare l'intera stringa nella shm, in quanto un processo non può accedere alla memoria di un altro processo. Tutte le gestioni sulle dimensioni ecc. le devi fare manualmente.Si questo l'ho capito, pero' io vorrei che ogni processo scrivi direttamente nella shared memory e possa scrivere solo un pezzo di stringa magari dalla posizione 4 alla 7. Questo perche' ogni processo ha solo dei pezzi di stringa e non tutta. Come faccio?

[B]
La dimensione è un multiplo di getpagesize() bytes (sugli x86 vale 4096 byte).
E' memoria grezza, come quella allocata con malloc.
Si ma che multiplo? Posso deciderlo io? A me serve una quantita' necessaria per metterci una stringa di SIZE dimensioni.

Thanx

ilsensine
21-10-2002, 11:17
Si questo l'ho capito, pero' io vorrei che ogni processo scrivi direttamente nella shared memory e possa scrivere solo un pezzo di stringa magari dalla posizione 4 alla 7. Questo perche' ogni processo ha solo dei pezzi di stringa e non tutta. Come faccio?
char *mem;
mem = (char *) shmat(id, NULL, 0);
...e tratti mem come la tua stringa, e ognuno scrive nella posizione che gli compete.


Si ma che multiplo? Posso deciderlo io? A me serve una quantita' necessaria per metterci una stringa di SIZE dimensioni.

int dim = <dimensione richiesta>;
dim = (dim+getpagesize()-1) & ~(getpagesize()-1);
id = shmget(__SHM_MAGIC__, dim, IPC_CREAT|0660);

Così "dim" è un multipo di pagina, e contiene almeno la dimensione che hai richiesto.

Cimmo
21-10-2002, 11:25
Originariamente inviato da ilsensine
[B]
char *mem;
mem = (char *) shmat(id, NULL, 0);
...e tratti mem come la tua stringa, e ognuno scrive nella posizione che gli compete.

Ok come mi avevi scritto...e come fai a scrivere nella posizione che gli compete? Infatti io lo so fare per le stringhe statiche e non quelle con puntatore. Per farla breve: io so che per le stringhe statiche uso strncpy(&str[4],token,strlen(token)); pero' non si puo' fare lo stesso se hai un puntatore ad una stringa, era quello che cercavo di chiedere.
[B]
int dim = <dimensione richiesta>;
dim = (dim+getpagesize()-1) & ~(getpagesize()-1);
id = shmget(__SHM_MAGIC__, dim, IPC_CREAT|0660);

Così "dim" è un multipo di pagina, e contiene almeno la dimensione che hai richiesto.
Fico...

cionci
21-10-2002, 11:32
Originariamente inviato da Cimmo
[B]
Ok come mi avevi scritto...e come fai a scrivere nella posizione che gli compete? Infatti io lo so fare per le stringhe statiche e non quelle con puntatore. Per farla breve: io so che per le stringhe statiche uso strncpy(&str[4],token,strlen(token)); pero' non si puo' fare lo stesso se hai un puntatore ad una stringa, era quello che cercavo di chiedere.

Fico...
Se sono terminare da '\0' va bene lo stesso metodo...o anche la più semplice strcpy...

ilsensine
21-10-2002, 11:34
Ok come mi avevi scritto...e come fai a scrivere nella posizione che gli compete? Infatti io lo so fare per le stringhe statiche e non quelle con puntatore. Per farla breve: io so che per le stringhe statiche uso strncpy(&str[4],token,strlen(token)); pero' non si puo' fare lo stesso se hai un puntatore ad una stringa, era quello che cercavo di chiedere.

Chi ha detto che non si può fare? :D

char a[64] = "salaam";
char *b = (char *) malloc(1024);
memcpy(&b[4], &a[1], 2);

nb1 al posto di &foo[x] puoi usare direttamente foo+x. Questo vale sia per stringhe statiche che allocate dinamicamente.
nb2 una stringa statica _è_ un puntatore char *, con l'unica differenza che non può cambiare il suo valore.

Cimmo
22-10-2002, 10:51
Originariamente inviato da ilsensine
[B]
Chi ha detto che non si può fare? :D

Infatti chi l'ha detto? Fuori i nomi... :D
Hai proprio ragione si usano tale e quale prima...
Adesso mi butto sui semafori...attenti alle pressime domande... :D

Cimmo
22-10-2002, 11:49
Originariamente inviato da ilsensine
[B]Ci sono i pthread_mutex, ma sono utilizzabili solo tra più thread. Non credo che mettendo uno di questi mutex nella memoria condivisa, e accedendoci da diversi processi, l'atomicità delle operazioni di lock sia assicurata.
Con i semafori comunque ottieni lo stesso risultato:

pthread_mutex_init <-> cmd.val=1; semctl(id, 0, SETVAL, cmd)
pthread_mutex_lock <-> buf.sem_op=-1; semop(id, &buf, 1)
pthread_mutex_unlock <-> buf.sem_op=1; semop(id, &buf, 1)
Quando compilo con i semafori mi dice:
host.c: In function `main':
host.c:89: storage size of `cmd' isn't known
host.c:89: warning: unused variable `cmd'

strano perche' invece cmd e' usato...

Altra cosa: se io ho bisogno di un'altra variabile condivisa: mi basta ripetere la shmget, posso farlo con le stesse variabili, tanto dopo che ho fatto la shmat il valore id restituito da shmget non mi serve piu'...giusto?
Pero' altra domanda: il valore di _SHM_MAGIC__ per cosa sta? Posso usarlo anche per la creazione della seconda variabile condivisa?

ciao

Cimmo
22-10-2002, 11:52
Originariamente inviato da Cimmo
[B]
Quando compilo con i semafori mi dice:
host.c: In function `main':
host.c:89: storage size of `cmd' isn't known
host.c:89: warning: unused variable `cmd'

strano perche' invece cmd e' usato...
A questa mi sono risposto da solo: non avevo messo la union iniziale...le altre domande pero' sono ancora valide :D

ilsensine
22-10-2002, 12:11
Altra cosa: se io ho bisogno di un'altra variabile condivisa: mi basta ripetere la shmget, posso farlo con le stesse variabili, tanto dopo che ho fatto la shmat il valore id restituito da shmget non mi serve piu'...giusto?
Se intendi creare un altro segmento condiviso, devi ripetere la shmget/shmat con un valore MAGIC differente. Ti consiglio però di utilizzare lo stesso segmento creato in precedenza, allocando spazio anche per le altre variabili (ovviamente devi stare attento alla loro posizione).

Pero' altra domanda: il valore di _SHM_MAGIC__ per cosa sta? Posso usarlo anche per la creazione della seconda variabile condivisa?

E' un identificativo per il tuo segmento condiviso; deve essere unico per tutto il sistema, e deve essere diverso per tutti i segmenti condivisi. In sostanza è il "nome" della regione condivisa.
Puoi vedere i segmenti allocati (e il relativo valore MAGIC, indicato in decimale con key) nel file /proc/sysvipc/shm (nella stessa directory trovi un file anche per i semafori).

Cimmo
22-10-2002, 12:50
Originariamente inviato da ilsensine
[B]
Se intendi creare un altro segmento condiviso, devi ripetere la shmget/shmat con un valore MAGIC differente. Ti consiglio però di utilizzare lo stesso segmento creato in precedenza, allocando spazio anche per le altre variabili (ovviamente devi stare attento alla loro posizione).

Ok nalla variabile dim ci metto spazio per tutto quello che voglio allocare.
Poi come chiamo le 2 shmat? Visto che dovra' darmi fuori 2 valori id uno per la prima variabile, uno per la seconda...
[B]
E' un identificativo per il tuo segmento condiviso; deve essere unico per tutto il sistema, e deve essere diverso per tutti i segmenti condivisi. In sostanza è il "nome" della regione condivisa.
Puoi vedere i segmenti allocati (e il relativo valore MAGIC, indicato in decimale con key) nel file /proc/sysvipc/shm (nella stessa directory trovi un file anche per i semafori).
Ma la memoria condivisa si dealloca alla chiusura del programma o la devo deallocare io?

ilsensine
22-10-2002, 13:06
Originariamente inviato da Cimmo [/i]
[B]
Ok nalla variabile dim ci metto spazio per tutto quello che voglio allocare.
Poi come chiamo le 2 shmat? Visto che dovra' darmi fuori 2 valori id uno per la prima variabile, uno per la seconda...
No, il segmento è unico. Sei tu che devi gestire la posizione degli elementi. Ad es. supponi di voler mettere anche un intero:

dim = MAX_DIM_STRINGA+sizeof(int);
id = shmget(...);
void *mem = shmat(id, ...);
char *spos = (char *) mem;
int *val = (int *) (spos+MAX_DIM_STRINGA);
(nb questo procedimento non funziona con gli sparc)


Ma la memoria condivisa si dealloca alla chiusura del programma o la devo deallocare io?
La memoria sopravvive all'uscita del programma, e se hai provato l'esempio che ho postato sulla shm capirai perchè.
Puoi renderlo "autodistruggente" quando il conteggio degli accessi è 0 usando il comando IPC_RMID con la shmctl (v. man).

Cimmo
22-10-2002, 16:38
Originariamente inviato da ilsensine
[B]
No, il segmento è unico. Sei tu che devi gestire la posizione degli elementi. Ad es. supponi di voler mettere anche un intero:

Fammi capire una cosa: quindi se faccio partire il programma 5 volte contemporaneamente lui becca sempre la stessa area di memoria?
Cio' non e' accettabile...praticamente e' cosi'...ogni istanza del mio software genera figli e tutti i figli e il padre condividono un paio di variabili...pero' tra diverse istanze del programma le variabili devono essere diverse...come faccio?
E se moltiplicassi il numero magico per il process id? Brutta idea?

cionci
22-10-2002, 16:47
Originariamente inviato da Cimmo
[B]E se moltiplicassi il numero magico per il process id? Brutta idea?
No...anzi dovrebbe essere giusta come idea...

ilsensine
22-10-2002, 16:50
Puoi:
1) usare un MAGIC diverso per ogni chiamata (sta a te decidere come generarlo, casualmente o per altre vie)
2) usare, al posto di MAGIC, il valore IPC_PRIVATE e passare in qualche modo l'id restituito da shmget ai child

ilsensine
22-10-2002, 16:51
E se moltiplicassi il numero magico per il process id? Brutta idea?
...allora usa direttamente il pid ;)

Cimmo
23-10-2002, 10:04
Ancora qualche dubbio:
1) il discorso dell'unicita' della memoria condivisa se si usa sempre lo stesso numero magico vale anche per i semafori? Cioe' il semaforo e' lo stesso se diverse istanze del programma usano lo stesso magic number?

2) se voglio mettere un secondo semaforo devo istanziare altre 2 variabili cmd e buf?

grazie
Cimmo

ilsensine
23-10-2002, 10:17
Originariamente inviato da Cimmo
Ancora qualche dubbio:
1) il discorso dell'unicita' della memoria condivisa se si usa sempre lo stesso numero magico vale anche per i semafori? Cioe' il semaforo e' lo stesso se diverse istanze del programma usano lo stesso magic number?
Certo, altrimenti non funziona nulla. Ricorda che puoi anche usare IPC_PRIVATE.


2) se voglio mettere un secondo semaforo devo istanziare altre 2 variabili cmd e buf?

Sono semplicemente variabili di appoggio; puoi riutilizzarle, se vuoi, oppure crearne altre.

Cimmo
23-10-2002, 10:26
Originariamente inviato da ilsensine
[B]
Certo, altrimenti non funziona nulla. Ricorda che puoi anche usare IPC_PRIVATE.


Sono semplicemente variabili di appoggio; puoi riutilizzarle, se vuoi, oppure crearne altre.
Quindi posso fare cosi':

id1=semget(__SEM_MAGIC__*getpid()*1, 1, IPC_CREAT|0660);
if (id1<0) fail("semget");
id2=semget(__SEM_MAGIC__*getpid()*2, 1, IPC_CREAT|0660);
if (id2<0) fail("semget");
cmd1.val=1;
cmd2.val=1;
if (semctl(id1, 0, SETVAL, cmd1)<0) fail("semctl");
if (semctl(id2, 0, SETVAL, cmd2)<0) fail("semctl");
buf1.sem_num=0;
buf1.sem_flg=SEM_UNDO;
buf2.sem_num=0;
buf2.sem_flg=SEM_UNDO;

Alla fine ho pensato che dovendo usare contemporaneamente i 2 semafori non posso usare le stesse variabili.
Come sem magic ho messo la costante per il process id (cosi' si differenzia da istanza a istanza) e moltiplicato x 1 e x 2 per differenziare i 2 semafori...

e' tutto ok?

ilsensine
23-10-2002, 10:43
Non farei assolutamente così.
Ricorda che con semget puoi allocare un array di semafori (v. man).
E non usare __SEM__MAGIC__*getpid()*x, meglio usare solo getpid() se ti basta un'unica allocazione, oppure IPC_PRIVATE e passare l'id restituito ai child (anzi, forse è la scelta migliore).

Cimmo
23-10-2002, 11:21
Originariamente inviato da ilsensine
[B]Non farei assolutamente così.
Ricorda che con semget puoi allocare un array di semafori (v. man).
E non usare __SEM__MAGIC__*getpid()*x, meglio usare solo getpid() se ti basta un'unica allocazione, oppure IPC_PRIVATE e passare l'id restituito ai child (anzi, forse è la scelta migliore).
Ecco un array di semafori e' quello che fa per me...
va bene se la istanzio cosi':

idsem=semget(getpid(), NUMSEM, IPC_CREAT|0660);
if (idsem<0) fail("semget");
cmd.val=1;
if (semctl(idsem, NUMSEM, SETVAL, cmd)<0) fail("semctl");
buf.sem_num=0;
buf.sem_flg=SEM_UNDO;

e poi quando richiamo un semaforo per dirgli quello che voglio usare devo modificare il campo buf.sem_num?
Nel senso voglio chiedere la mutua esclusione del 20esimo semafaro va bene se faccio:

buf.sem_num=19;
buf.sem_op=(-1);
if (semop(idsem, &buf, 1)<0) fail("semop");

ilsensine
23-10-2002, 11:24
idsem=semget(getpid(), NUMSEM, IPC_CREAT|0660);
if (idsem<0) fail("semget");
cmd.val=1;
[B]for(int x=0; x<NUMSEM; ++x)
if (semctl(id, x, SETVAL, cmd)<0) fail("semctl");[/B]
buf.sem_num=0;
buf.sem_flg=SEM_UNDO;


e poi quando richiamo un semaforo per dirgli quello che voglio usare devo modificare il campo buf.sem_num?
Esatto

Cimmo
23-10-2002, 11:26
Forse volevi scrivere cosi'? Non avrebbe senso il for senno'...
for(int x=0; x<NUMSEM; ++x) {
if (semctl(id, x, SETVAL, cmd)<0) fail("semctl");
}

Cimmo
23-10-2002, 11:27
Ok hai appena editato e modificato...ma perche' il ++x? Cosi' il primo valore sara' 1...non capisco...

ilsensine
23-10-2002, 11:43
Originariamente inviato da Cimmo
[B]Ok hai appena editato e modificato...ma perche' il ++x? Cosi' il primo valore sara' 1...non capisco...
...sicuro? ;)

Cimmo
23-10-2002, 11:56
Originariamente inviato da ilsensine
[B]
...sicuro? ;)
Ehm...:confused:
ma ++x non preincrementa e x++ postincrementa? Perche' fanno la stessa cosa mettendoci ++x o x++ ?

ilsensine
23-10-2002, 12:01
int x1 = 1;
int x2 = 1;
++x1;
x2++;
printf("x1: %d x2: %d\n", x1, x2);

ilsensine
23-10-2002, 12:03
int x1 = 1;
int x2 = 1;
int y1;
int y2;
y1 = ++x1;
y2 = x2++;
printf("y1: %d y2: %d\n", y1, y2);


Succo: nella for, utilizzo forse il valore restituito da ++x all'atto dell'incremento? No.

Cimmo
23-10-2002, 16:03
Originariamente inviato da ilsensine
[B]
int x1 = 1;
int x2 = 1;
int y1;
int y2;
y1 = ++x1;
y2 = x2++;
printf("y1: %d y2: %d\n", y1, y2);


Succo: nella for, utilizzo forse il valore restituito da ++x all'atto dell'incremento? No.
Ok ma prova questo

int x1=0;
int x2=0;
printf("%d %d",++x1,x2++);

probabilmente il for usa quella regola sempre alla fine del ciclo ed e' un caso speciale, pero' ++x e' diverso da x++!!!

ilsensine
23-10-2002, 16:07
printf("%d %d",++x1,x2++);

Stai passando alla printf il risultato di ++x/x++. Nel terzo argomento della for invece esegui una operazione, che può essere qualsiasi, senza preoccuparti di un eventuale risultato.

ilsensine
23-10-2002, 16:11
Guarda ad es. che puoi fare nel terzo argomento della for:

int main() {
int x;
char a[64];
for(x=0; x<5; (
sprintf(a, "%d", x++),
fclose(fopen(a, "w"))
));
return 0;
}

Come vedi, la for se ne frega altamente di quello che succede lì dentro ;)

Cimmo
24-10-2002, 11:38
Una conferma: se io uso l'array di semafori, pero' 2 processi possono chiedere la mutuaesclusione contemporaneamente su 2 semafori diversi, io non posso usare la stessa variaibile di appoggio buf, senno' c'e' conflitto...giusto?

ilsensine
24-10-2002, 11:46
Sì la puoi usare, a meno che qualche sem* non la modifichi.
Nota che bloccare due diversi semafori di seguito è un BUG che prima o poi ti porta al deadlock.

Cimmo
24-10-2002, 11:53
Originariamente inviato da ilsensine
[B]Sì la puoi usare, a meno che qualche sem* non la modifichi.
Nota che bloccare due diversi semafori di seguito è un BUG che prima o poi ti porta al deadlock.
Gia' perche' ogni figlio si fa una copia delle variabili, quindi quelle che usa non sono in comune.
Perche' e' un bug? Se io ho un array di semafori, dove ad ogni semaforo corrisponde una risorsa differente che deadlock puo' portare?

ciao
Cimmo

ilsensine
24-10-2002, 11:57
Perche' e' un bug? Se io ho un array di semafori, dove ad ogni semaforo corrisponde una risorsa differente che deadlock puo' portare?

Caso più semplice: prendi due processi A, B e due semafori 1, 2:

A: lock semaforo 1 (ok)
B: lock semaforo 2 (ok)
A: lock semaforo 2 (in attesa)
B: lock semaforo 1 (in attesa)
=> deadlock

Potresti usare la semop per effettuare i DUE lock contemporaneamente in maniera atomica, ma la bomba è sempre innescata - se riesci a tenere solo un lock alla volta è meglio.

Cimmo
24-10-2002, 12:01
Si ma ogni processo da me non prende la mutuaesclusione di piu' di 1 semaforo alla volta, per prenderne un secondo deve prima rilasciare la prima risorsa...c'e' qualche controindicazione?

ilsensine
24-10-2002, 12:04
Originariamente inviato da Cimmo
[B]Si ma ogni processo da me non prende la mutuaesclusione di piu' di 1 semaforo alla volta, per prenderne un secondo deve prima rilasciare la prima risorsa...c'e' qualche controindicazione?
Allora ok, avevo capito il contrario.

Cimmo
24-10-2002, 21:57
Urgente: ma io non posso aprire piu' di un listening socket per processo? Perche' io faccio mettere piu' di un processo in ascolto di connect tcp, ma dopo che il primo si e' messo in ascolto, dal secondo processo in poi la bind mi restituisce: Err: 98 "Address already in use"

Se dovesse essere cosi', io come faccio ad avere una ricezione contemporanea di dati?

cionci
24-10-2002, 22:31
Chiaro che la bind non ti permette di stare in ascolto sulla stessa porta...
Ci sono diversi modi...

1)
Sul processo padre :
socket
bind
listen
accept

Appena ricevi una connessione fai la fork...ad a quel punto sul figlio gestisci il socket ricevuto dalla accept...mentre nel padre ritorni sulla accept...

Se non hai problemi di prestazioni (creare un nuovo processo con la fork è molto peso) va benissimo...

2) Produttore-consumatore (prefork)
Fai N fork per i consumatori (N figli)...
I figli restano in attesa su una coda che arrivi una connessione da gestire...
Hai un produttore (processo padre) che sta in attesa di ricevere connessioni sulla accept...
Appena ne riceve una mette il socket nella coda...e ritorna in attesa di una connessione...
Il primo processo figlio che viene sbloccato si prende il socket e gestisce la connessione...

Per gestire la coda devi usare 2 semafori e una mutua esclusione...

N è il numero di figli...
Si inizializza SemA a N, SemB a 0...

Immissione :

Lock(SemA)
Lock(mutex)
immetto in coda
Unlock(mutex)
Unlock(SemB)

Prelievo :

Lock(SemB)
Lock(mutex)
immetto in coda
Unlock(mutex)
Unlock(SemA)

3) thread...anche in Linux ci dovrebbero essere i thread (pthread)
Usandoli puoi benissimo recuperare un bel po' di prestazioni sul primo metodo...

ilsensine
25-10-2002, 08:10
creare un nuovo processo con la fork è molto peso
Se la creazione del nuovo processo prevede un execve o simili, è molto meglio usare una vfork.

cionci
25-10-2002, 08:30
Originariamente inviato da ilsensine
[B]
Se la creazione del nuovo processo prevede un execve o simili, è molto meglio usare una vfork.
vfork che fa ? Non duplica la memoria del processo padre ?

ilsensine
25-10-2002, 08:42
Fork è implementata con fork, vfork è implementata con clone.
Non esiste una definizione rigorosa della vfork; sotto linux evita la copia completa della page table del processo padre, in quanto è studiata appositamente per essere lanciata prima di un exec (che sovrascriverebbe comunque la page table).
Nota che su Linux anche la fork non è molto pesante: viene duplicata la page table tra padre e figlio, ma non le pagine di memoria fisica. Le pagine di memoria vengono duplicate nel momento in cui uno dei due tenta una scrittura. Ciò è molto efficiente e comporta:
- miglior gestione della memoria (le pagine che verranno solo lette non vengono duplicate)
- minor latenza della fork

Cimmo
29-10-2002, 15:28
Originariamente inviato da ilsensine
[B]
La memoria sopravvive all'uscita del programma, e se hai provato l'esempio che ho postato sulla shm capirai perchè.
Puoi renderlo "autodistruggente" quando il conteggio degli accessi è 0 usando il comando IPC_RMID con la shmctl (v. man).
Quindi per liberare la memoria al termine del programma mi basta fare cosi':
shmctl(id,IPC_RMID,??);
Come terzo parametro che ci devo mettere?

Anche i semafori rimangono in memoria? O si autoeliminano al termine del programma?

Thanx...

P.S.= Sto facendo un software niente male...

ilsensine
29-10-2002, 15:47
Quindi per liberare la memoria al termine del programma mi basta fare cosi':
shmctl(id,IPC_RMID,??);
Come terzo parametro che ci devo mettere?
Non è specificato, ma credo che sia ignorato, quindi dovrebbe poter essere NULL.

Anche i semafori rimangono in memoria? O si autoeliminano al termine del programma?
Come per la shm, possono essere distrutti con la semctl(.., 0, IPC_RMID)
Controlla la pagina man per vedere cosa succede quando rimuovi un set di semafori.

Cimmo
29-10-2002, 16:29
Originariamente inviato da ilsensine
[B]
Non è specificato, ma credo che sia ignorato, quindi dovrebbe poter essere NULL.


Come per la shm, possono essere distrutti con la semctl(.., 0, IPC_RMID)
Controlla la pagina man per vedere cosa succede quando rimuovi un set di semafori.
La semctl dice che il secondo parametro viene ignorato, quindi dovrebbe eliminare con un solo comando anche un array di semafori come ho io nel mio caso, giusto?

Altra domanda:
ho usato il metodo strnlen di string.h e in fase di compilazione mi da' questo warning: host.c: In function `main': host.c:436: warning: implicit declaration of function `strnlen'
in teoria non dovrebbe essere un errore che appare quando non includi il file header? Eppure ho incluso un file .h che a sua volta include string.h quindi non capisco perche' non lo trova...

ilsensine
29-10-2002, 16:37
Compila con -D_GNU_SOURCE

Cimmo
29-10-2002, 17:04
Originariamente inviato da ilsensine
[B]Compila con -D_GNU_SOURCE
Uh...funzia! Ma che vuol dire? Sul man non ho trovato niente...

ilsensine
29-10-2002, 19:21
...segreti del mestiere :D
(...e una omissione/dimenticanza nella pagina man)

Cimmo
29-10-2002, 19:45
Originariamente inviato da ilsensine
[B]...segreti del mestiere :D
(...e una omissione/dimenticanza nella pagina man)
No dai adesso sono curioso...:D

ilsensine
29-10-2002, 20:19
Alcune funzionalità delle libc sono proprie di standard particolari e non sono disponibili a meno di definire delle macro specifiche. Definendo _GNU_SOURCE hai accesso a tutte le funzionalità delle libc.
Altri esempi sono:
sched_yield()
formato esteso di sigaction
strndup
ecc.

Cimmo
30-10-2002, 11:18
Se io ho un server con un certo indirizzo ip: e ho n figli che cercano di aprire listening socket in mutua esclusione senno' la bind si arrabbia, perche' assegna 2 volte lo stesso socketfd a 2 client differenti che si sono collegati?
C'e' qualche variabile che devo condividere con tutti gli n figli?

ilsensine
30-10-2002, 12:37
Quando un processo forka, i due processi risultanti avranno una propria storia. Quindi un fd di uno sarà un descrittore a parte rispetto l'fd dell'altro, indipendentemente che abbiano o no lo stesso valore. Solo gli fd già aperti possono venir ereditati dal child, ma in tal caso viene in effetti duplicato il descrittore da condividere.

Cimmo
30-10-2002, 12:53
Originariamente inviato da ilsensine
[B]Quando un processo forka, i due processi risultanti avranno una propria storia. Quindi un fd di uno sarà un descrittore a parte rispetto l'fd dell'altro, indipendentemente che abbiano o no lo stesso valore. Solo gli fd già aperti possono venir ereditati dal child, ma in tal caso viene in effetti duplicato il descrittore da condividere.
Urca! Quindi se A1 si connette con B1 e A2 si vuole connettere con B2 non puo' sfruttare lo stesso socketfd della connessione A1-B1?
A1 e A2 sono figli di A con lo stesso indirizzo e stessa cosa dicasi per B1 e B2.

ilsensine
30-10-2002, 13:43
Urca! Quindi se A1 si connette con B1 e A2 si vuole connettere con B2 non puo' sfruttare lo stesso socketfd della connessione A1-B1?
No, devi fare una connect() a parte, altrimenti useresti lo stesso canale di comunicazione di A1, e succede un casino.

Cimmo
30-10-2002, 13:54
Originariamente inviato da ilsensine
[B]
No, devi fare una connect() a parte, altrimenti useresti lo stesso canale di comunicazione di A1, e succede un casino.
Infatti per ora il mio software ha un sacco di anomalie.
Per capire meglio se io ho A1 che si connette a B1 e voglio che anche A2 e B2 si connettano insieme devo fare 2 connessioni completamente differenti? Questo anche se sono entrambi figli di A (A1 e A2) e quindi hanno lo stesso indirizzo e porta ip?

In alternativa non e' fattibile che io allacci una connessione tra A e B (i padri) e poi tutti i figli di A (A1, A2...) possono usare il canale e cosi' anche tutti i figli di B (B1, B2...).
Questo e' molto importante, grazie ancora per rispondere sempre tempestivamente alle domane, sto facendo un progetto per niente semplice...

ilsensine
30-10-2002, 14:11
Non capisco qual è il problema...
A dovrebbe stare in listen e creare un child ad ogni nuova connessione, ok?
Ogni figlio By di B effettua una connect() con A, il quale crea un child Ax per gestire la connessione...in genere si fa così

Cimmo
30-10-2002, 14:18
Ok io invece prima creavo il figlio e poi la connessione veniva generata dallo stesso figlio, speravo poi di poter recuperare da un altro figlio la connessione avvenuta mantenendo lo stesso socketfd, ma cosi' non funzia...
ma io posso fare cosi'?

1) il padre crea il figlio
2) il figlio si mette in attesa che il padre gli procuri una connessione
3) il padre crea tutti i figli che si mettono in attesa
4) il padre si mette in attesa di una connessione appena gliene arriva una lui passa il numero del socketfd al/ai figlio/i interessati e poi ritorna al punto 4) cioe' in attesa di altre connessioni.

E' un po' diverso dal aspettare la connessione e poi creare, pero' mi sembra che il conto torni...o mi sbaglio?

ilsensine
30-10-2002, 15:49
Ok certo, se vuoi perdere tutti i capelli prima del tempo, è la procedura migliore :D

Cimmo
30-10-2002, 16:14
Originariamente inviato da ilsensine
[B]Ok certo, se vuoi perdere tutti i capelli prima del tempo, è la procedura migliore :D
Alt...fermi tutti!
Ma se io devo fare gestire tutto dal padre, come faccio contemporaneamente a mettermi in ascolto e a connettermi? Questo perche' il programma che sto cercando di fare fa sia da server che da client, quindi fino a poco fa, un client si collegava al server (erano 2 figli differenti di 2 istante differenti non so se ho reso l'idea) ora pero' se il padre si mette in ascolto, quello si inchioda li' e come faccio contemporaneamente a cercare di connettermi?
ARGH AIUTO!

ilsensine
30-10-2002, 16:26
Non intendevo di far fare tutto a un padre, ma di creare i child solo quando servivano, per uno scopo ben preciso, e in maniera che possano essere autonomi una volta creati e inizializzati.
Cmq dovresti analizzare l'opportunità di usare i pthread al posto di processi distinti (è più facile l'ipc, non serve shm, semafori o altro).

cionci
30-10-2002, 16:47
Originariamente inviato da Cimmo
[B]Alt...fermi tutti!
Ma se io devo fare gestire tutto dal padre, come faccio contemporaneamente a mettermi in ascolto e a connettermi?
Puoi fare un processo figlio che ascolta e che crea altri figli...
Il primo processo crea inoltre un altro processo figlio client quando serve (se puoi gestire più client contemporaneamente, altrimenti è lo stesso processo padre che fa da client)...

Segui il consiglio di ilsensine sui pthread... I thread a differenza dei processi sono a memoria comune ;)

Cimmo
30-10-2002, 18:02
Originariamente inviato da cionci
[B]
Puoi fare un processo figlio che ascolta e che crea altri figli...
Il primo processo crea inoltre un altro processo figlio client quando serve (se puoi gestire più client contemporaneamente, altrimenti è lo stesso processo padre che fa da client)...

Segui il consiglio di ilsensine sui pthread... I thread a differenza dei processi sono a memoria comune ;)
Il problema e' questo (e' difficile da spiegare) ogni istanza del mio software ha una parte server e una client. Siccome il server puo' ricevere una connessione che puo' servire anche al client volevo fargli usare la stessa connessione senza fare casini. Quindi all'inizio facevo creare un figlio per ogni client/server e il primo che si connetteva dava il socketfd all'altro, ma questo mi sembra di aver capito non funzia.
Ora:
se io creo un primo figlio che si mette in ascolto e poi appena si connette a sua volta crea un figlio che gestisce la connessione ok questo il lato server, il lato client pero' dove lo metto? Faccio fare un secondo figlio al padre e poi cerco a sua volta di connettermi e se ci riesco creo un figlio? Pero' in questo caso e' sempre la stessa storia la connessione raggiunta dal client o dal server non e' gestibile dall'altra parte.
Mi sono spiegato? Se no vi faccio pure un disegno pure di farvi capire...rispondetemi sono in kernel panic :D

cionci
30-10-2002, 18:13
Spiegami meglio...
Il server quante connessioni accetta ? Una sola ?
E il client a quenti server si può conenttere ?

Cimmo
30-10-2002, 18:45
Originariamente inviato da cionci
[B]Spiegami meglio...
Il server quante connessioni accetta ? Una sola ?
E il client a quenti server si può conenttere ?
Il server ne accetta una sola alla volta, ma alla fine ne possono arrivare piu' d'una.
Il client puo' anche lui connettersi da 0 a n host. Siccome molte volte il client e il server della stessa istanza del software possono (ma non e' detto) connettersi allo stesso host (che altro non e' che un'altra istanza del medesimo software) vorrei che questa connessione venga condivisa!
Ti spedisco anche un disegno scannerizzato per rendere l'idea...immagina che di istanze del mio software ce ne puo' essere da 1 a n anche per quella.
Spero di essere stato piu' chiaro...fammi sapere...

cionci
30-10-2002, 19:05
Un processo "listener" sta in ascolto con la accept su una porta...
Ogni volta che riceve una connessione in ingresso lancio un processo "chat" (la chiamo chat anche se magari no lo è, ma rende bene l'idea)...

Un altro processo chiamo "connector" ha il compito di creare una nuova connessione verso un "listener"...

Il processo "chat" è lo stesso sia per il "listener" che per il "connector" ed ha bisogno solamente del socket creato da uno dei due processi...
Su questo socket viaggeranno sia i dati in uscita che quelli in ingresso...

Se non hai grossi problemi di prestazioni credo che tu possa usare sia send che receive non bloccanti nello stesso processo...
Oppure lanci un altro processo che si occupa di trasmettere e ricevere i dati...con send bloccanti e receive non bloccanti...

Cimmo
30-10-2002, 19:21
Quindi tu dici cosi' (schematizzo molto)
con P indico il PADRE "listener"
con CH indico il figlio "chat" che si occupa della connessione in ingresso
con CN indico "connector" il figlio che tenta di connettersi

P: fork // creo CH
CH: attendo una connessione per me che viene accettata solo da mio padre P
P: fork //creo CN
CN: tento di connettermi, se ci riesco passo il socketfd a CH nel caso gli serva
P: aspetto connessioni da CN (non dal mio figlio, ma da CN generati da altre istanze del mio software) appena me ne arriva una passo il socketfd al mio CH di competenza.

Cosi' funziona in entrambi i casi?
caso 1) Mettiamo che il CN riesca a connettersi e deve condividere la connessione con il CH se gli passo il socketfd funzia?
caso 2) Il P riceve una connessione e la passa a CH e qui ok, poi magari serve anche al CN gli passa il socketfd funzia?

E questo che deve risultare...una sola connessione per 2 processi!

cionci
30-10-2002, 19:31
Io farei così :

Il processo princiapale può essere "Connector"...

Connector
fork
     Listener
     while(1) {
     aspetto sulla accept
     fork
          Chat
     }
while(1) {
Aspetto che venga richiesta una connessione
fork
     Chat
}

Ogni processo "Chat" ha il suo socket su cui fa una connessione bidirezionale...

Cimmo
30-10-2002, 19:54
No aspetta non ho capito: ogni processo Chat che cosa deve fare? Nel senso che io avevo gia' fatto una cosa simile facendo passare i socketfd, ma ilsensine mi ha detto che non funzia, perche' essendo processi differenti non hanno in comune i file descriptor...come devo fare di preciso? Come fanno i 2 processi chat a condividere la medesima connessione (qualora ne venga il bisogno?)

cionci
31-10-2002, 08:26
Allora usa i thread ;)
Non una grande esperienza di programmazione multiprocesso in Linux...mi dispiace...

Cimmo
31-10-2002, 09:44
Originariamente inviato da ilsensine
[B]Non intendevo di far fare tutto a un padre, ma di creare i child solo quando servivano, per uno scopo ben preciso, e in maniera che possano essere autonomi una volta creati e inizializzati.
Cmq dovresti analizzare l'opportunità di usare i pthread al posto di processi distinti (è più facile l'ipc, non serve shm, semafori o altro).
Ciao ilsensine, non so se hai seguito il resto della vicenda...mi sembra di aver capito che o uso i pthread o m'attacco...come si usano? Sono facili come le fork? E soprattutto condivido veramente tutto? Se si' come faccio ad avere delle variabili autonome?

Thanx...

ilsensine
31-10-2002, 10:04
Originariamente inviato da Cimmo
[B]
Ciao ilsensine, non so se hai seguito il resto della vicenda...mi sembra di aver capito che o uso i pthread o m'attacco...come si usano? Sono facili come le fork? E soprattutto condivido veramente tutto? Se si' come faccio ad avere delle variabili autonome?

Thanx...
I pthread sono molto simili ai thread sotto windows. Hai mai lavorato con cose simili?

Cimmo
31-10-2002, 10:07
Originariamente inviato da ilsensine
[B]
I pthread sono molto simili ai thread sotto windows. Hai mai lavorato con cose simili?
No non ho mai lavorato, ho lavorato solo con le fork sotto Linux. Pero' devo imparare ed in fretta...saresti disponibile per una chiacchierata su IRC? Visto che secondo me il forum e' un po' lento per fare botte e risposte...se mi dici di no lo capisco...e' solo che sto facendo un progetto per l'universita' (faccio informatica a Bologna) e sono in ritardissimo...

ciao
Cimmo

ilsensine
31-10-2002, 10:32
Non è necessario, sono semplici da usare, ti faccio un breve howto:

Include necessario:
#include <pthread.h>
Quando compili, linka con le libpthread ( -lpthread )

Un thread è un "processo nel processo"; condivide tutta la memoria e i descrittori di file con gli altri thread; ogni thread ha uno stack ("stato") proprio.

Creazione di un thread:
pthread_t newthread;
pthread_create(&new_thread, NULL, funzione, parametro);

dove:
"funzione" è una funzione di prototipo void *(*) (void *); ad es.
void *funzione (void *parametro)
Questa funzione sarà l'inizio del nuovo thread.
parametro è un void * generico; è un parametro che puoi passare al thread, a tua discrezione.
Quando un thread termina deve chiamare
pthread_exit(void *retval)
dove retval è il parametro di "uscita" del thread, semmai ne hai bisogno.

Esempio:


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

void *th_fnc(void *data) {
int param = (int) data;
for(;;) {
fprintf(stderr, "thread %d parametro %d\n", getpid(), param);
sleep(1);
}
}

int main() {
pthread_t unused;
pthread_create(&unused, NULL, th_fnc, (void *) 1);
pthread_create(&unused, NULL, th_fnc, (void *) 2);
for(;;) {
fprintf(stderr, "thread padre\n");
sleep(1);
}
return 0;
}



Nota che i thread possono accedere in maniera concorrente a _tutti_ i dati globali, funzioni o altro del processo corrente. Ovviamente ti servono delle strategie di lock, che fanno uso dei pthread_mutex:

Inizializzazione di un mutex:
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);

Lock di un mutex (equivalente a "EnterCriticalSection" di Windows)
pthread_mutex_lock(&mutex)
oppure pthread_mutex_trylock(&mutex) per la forma non bloccante (altrimenti il lock è bloccante se il mutex è loccato da qualcun altro).

Unlock di un mutex:
pthread_mutex_unlock(&mutex);

Distruzione di un mutex non più necessario:
pthread_mutex_destroy(&mutex);

Esempio:


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

int x = 0;
int y = 0;
pthread_mutex_t mtx;

void *th_fnc(void *unused) {
for(;;) {
pthread_mutex_lock(&mtx);
/* Senza il lock, l'incremento di x e y non sarebbe atomico */
x++;
y++;
fprintf(stderr, "thread %d (x,y)= (%d,%d)\n", getpid(), x, y);
pthread_mutex_unlock(&mtx);
sleep(1);
}
}

int main() {
pthread_t unused;
pthread_mutex_init(&mtx, NULL);

pthread_create(&unused, NULL, th_fnc, NULL);
pthread_create(&unused, NULL, th_fnc, NULL);
for(;;) sleep(1);
return 0;
}


Le pagine man sono ricche di ulteriori dettagli, ma questo è il 90% di quello che ti serve.

Cimmo
31-10-2002, 10:40
Ok grazie e 1000, adesso mi metto al lavoro...ma una cosa sulle variabili:

1) se io dichiaro una variabile nel main (padre) poi creo dei thread questa e' condivisa da tutti? Nel senso il primo thread che la cambia, la cambia per tutti?
2) se voglio fare una variabile privata di un thread, mi basta dichiararla all'interno della sua funzione?

P.S.= Usando i thread ottimizzo automaticamente per i Pentium 4 HT :D
P.P.S.= C'e' un baco nel forum...anche se specifichi /CODE ti valuta lo stesso le faccine...sbagliato secondo me...infatti ha riconosciuto il punto e virgola e la parentesi della fine del for...

ilsensine
31-10-2002, 10:46
1) se io dichiaro una variabile nel main (padre) poi creo dei thread questa e' condivida da tutti? Nel senso il primo thread che la cambia, la cambia per tutti?
Certo, questo è il vantaggio principale dei thread. Sotto linux ciascun thread è implementato come un processo, ma un gruppo di thread condivide _tutta_ la memoria.


2) se voglio fare una variabile privata di un thread, mi basta dichiararla all'interno della sua funzione?
Certo, in quanto le variabili locali a una funzione finiscono nello stack, e ogni thread ha un suo stack.

P.S.= Usando i thread ottimizzo automaticamente per i Pentium 4 HT :D
...al pari di quanto ottimizzeresti con i processi.
P.P.S.= C'e' un baco nel forum...anche se specifichi /CODE ti valuta lo stesso le faccine...sbagliato secondo me...infatti ha riconosciuto il punto e virgola e la parentesi della fine del for...
Ho disabilitato le faccine ;)

Cimmo
31-10-2002, 15:33
Originariamente inviato da ilsensine
[B]Non è necessario, sono semplici da usare, ti faccio un breve howto:

Creazione di un thread:
pthread_t newthread;
pthread_create(&new_thread, NULL, funzione, parametro);

Quando un thread termina deve chiamare
pthread_exit(void *retval)
dove retval è il parametro di "uscita" del thread, semmai ne hai bisogno.

Dunque ho gia' convertito tutto in thread, solo che prima di tutto, mi sembra che mettendo pthread_exit(NULL); nei thread da creare il programma non esegue contemporaneamente il suo codice e quello del figlio thread, ma esegue solo il codice del figlio e quando arriva al pthread_exit il software termina.
Se invece non lo metto mi dice in fase di compilazione:

host.c: In function `thReceive':
host.c:434: warning: control reaches end of non-void function
host.c: In function `thSend':
host.c:538: warning: control reaches end of non-void function

strano perche' le 2 funzioni sono void, dalle tue differiscono solo che prendono un puntatore ad un int come input.

Che cosa sta succedendo?

ilsensine
31-10-2002, 16:14
Dunque ho gia' convertito tutto in thread, solo che prima di tutto, mi sembra che mettendo pthread_exit(NULL); nei thread da creare il programma non esegue contemporaneamente il suo codice e quello del figlio thread, ma esegue solo il codice del figlio e quando arriva al pthread_exit il software termina.
?

Se invece non lo metto mi dice in fase di compilazione:

host.c: In function `thReceive':
host.c:434: warning: control reaches end of non-void function
host.c: In function `thSend':
host.c:538: warning: control reaches end of non-void function

strano perche' le 2 funzioni sono void, dalle tue differiscono solo che prendono un puntatore ad un int come input.

Non sono void, bensì void *.
Usando pthread_exit non ottieni quel warning in quanto è una funzione dichiarata con __attribute__ ((__noreturn__)) (in soldoni: non ritorna mai - ma questo è ovvio)

Cimmo
31-10-2002, 16:23
Originariamente inviato da ilsensine
[B]
?


Non sono void, bensì void *.
Usando pthread_exit non ottieni quel warning in quanto è una funzione dichiarata con __attribute__ ((__noreturn__)) (in soldoni: non ritorna mai - ma questo è ovvio)
Io li richiamo cosi':

for (i=0; i<=(TotHosts-1); i++)
{
if ((i!=numHost) && (network[0][i].byteReceived>0))
pthread_create(&unused,NULL,thReceive(&i),NULL);

if ((i!=numHost) && (i!=0) && (network[0][i].byteSent>0))
pthread_create(&unused,NULL,thSend(&i),NULL);
}

Ogni istanza esegue il primo if (cioe' il primo thread) non concorrentemente (non so perche') e finito il thread (arrivati a pthread_exit) termina l'istanza (tutto il programma)! E perche' le altre chiamate, il for ecc. non vengono eseguite?

ilsensine
31-10-2002, 16:30
...,thReceive(&i)...

Ehm...
:D
Che è 'sta roba? :cool:

Cimmo
31-10-2002, 16:32
Originariamente inviato da ilsensine
[B]
Ehm...
:D
Che è 'sta roba? :cool:
Per passargli l'indirizzo della variabile i ... non va bene?

ilsensine
31-10-2002, 16:38
Cerrrto che no :D
Così stai _chiamando_ la funzione
Riguardati bene il mio primo esempio; il parametro si passa così:

pthread_create(&unused,NULL,thReceive,(void *) i);

ilsensine
31-10-2002, 16:41
Nota inoltre che devi passare il valore di i, non il suo indirizzo, altrimenti ora che il thread legge il valore...il ciclo for l'ha già modificato!

Cimmo
31-10-2002, 16:55
Originariamente inviato da ilsensine
[B]Cerrrto che no :D
Così stai _chiamando_ la funzione
Riguardati bene il mio primo esempio; il parametro si passa così:
pthread_create(&unused,NULL,thReceive,(void *) i);

Ok l'ho chiamata come hai detto tu: poi nel codice della funzione ho messo:
int i=(int) toHost;

e la funzione l'ho dichiarata cosi': void *thSend(void *toHost)

va bene?

ilsensine
31-10-2002, 17:06
Sì, è corretto.
Nota che se devi passare più di un parametro al thread, la procedura comune è allocare dinamicamente una struttura apposita, e passare il puntatore al thread. Sarà compito del thread, quando termina, deallocare la struttura.

Cimmo
31-10-2002, 17:12
Un'altra cosa:
per le risorse in comune: devo gestire la mutua esclusione solo quando la risorsa viene modificata, se una risorsa non viene modificata e viene soltanto letta non ha senso che metta la mutua esclusione giusto?

cionci
31-10-2002, 17:35
Se la struttura non la modifica nessuno non serve la mutua esclusione...ma se può essere modificata anche da uno solo dei thread, mentre gli altri potrebbero essere in lettura della stessa...allora va usata la mutua esclusione...

Cimmo
31-10-2002, 17:58
Questo e' il 102esimo messaggio di questo thread, c'e' ancora qualcosina che non funziona, ma penso di aver capito che cosa. Per oggi pero' mi fonde la testa...grazie a tutti...a domani!

P.S.= I thread ora funzionano...il problema sta da un'altra parte...

Cimmo
01-11-2002, 13:35
HO RISOLTO!!!!!
I thread funzionano alla grande!!!!
Grazie ilsensine e grazie cionci!
Senza di voi mi sa che a questo punto mi attaccavo!!!

Quando avro' finito le ultime rifiniture se vorrete vi daro' il software da testare e vi diro' a cosa serve...

ciao ciao
Cimmo

Cimmo
05-11-2002, 10:56
Problemino con i thread, ho il seguente codice:

for (r=1; r<TotHosts; r++)
{
int socketfd;
struct thInfo thVar;

thVar.socketfd=socketfd;
thVar.toHost=r;
pthread_create(&unused,NULL,thSendNetMapRuleAndData,(void *) &thVar);
....
}
void *thSendNetMapRuleAndData(void *info)
{
int socketfd,r;
struct thInfo *thInfoTemp;

thInfoTemp=(struct thInfo *) info;
r=(*thInfoTemp).toHost;
socketfd=(*thInfoTemp).socketfd;
...
}

essendo che il for crea un thread e gli passa la struttura, poi passa a creare gli altri thread contemporaneamente. Il fatto e' che se fa prima il padre a creare un altro thread sovrascrive le informazioni presenti nella struttura thVar e cosi' 2 thread hanno le stesse informazioni...e cio' e' SBAGLIATO.
Il problema e' la struttura che e' passata per riferimento, se fosse passata per valore sarebbe tutto ok...che posso fare?

ilsensine
05-11-2002, 11:06
for (r=1; r<TotHosts; r++)
{
int socketfd;
[B]struct thInfo *thVar = (struct thInfo *) malloc(sizeof(struct thInfo));

thVar->socketfd=socketfd;
thVar->toHost=r;
pthread_create(&unused,NULL,thSendNetMapRuleAndData,(void *) thVar);[/B]
....
}
void *thSendNetMapRuleAndData(void *info)
{
int socketfd,r;
struct thInfo *thInfoTemp;

thInfoTemp=(struct thInfo *) info;
r=(*thInfoTemp).toHost;
socketfd=(*thInfoTemp).socketfd;
...
[B] free(info);
pthread_exit(retcode);[/B]
}

Cimmo
05-11-2002, 11:13
Gia' mi stava venendo fuori anche a me (sul serio) pero' mi hai preceduto...scusa ilsensine ti faccio una domanda un po' "molesta":
non e' che sai rispondermi alle domande fatte nella parte di Linux, sulla JVM e sui serivizi? Io ho aiutato mezzo mondo in questi giorni, ma nessuno sa rispondere alle mie domandine... :(

ilsensine
05-11-2002, 11:56
Io e Java siamo due mondi a parte ;)

Cimmo
05-11-2002, 12:19
Ho fatto una cosa simile nell'altro file...questa volta devo passare solo un intero pero' mi fa dei casini:

for (r=1; r<TotHosts; r++)
{
int *toH=(int *) malloc(sizeof(int));

(*toH)=i;

pthread_create(&unused,NULL,thSendNetMapRuleAndData,(void *) toH);
....
}
void *thSendNetMapRuleAndData(void *toHost)
{
int i,*itmp;

itmp=(int *) toHost;
i=(*itmp);
...
free(toHost);
pthread_exit(NULL);
}

dove ho sbagliato?

ilsensine
05-11-2002, 12:31
Non ho idea. Nota però che se devi passare solo un intero è inutile la malloc, in quanto viene passato per copia (guarda il mio esempio sui pthread).

Cimmo
05-11-2002, 12:39
Originariamente inviato da ilsensine
[B]Non ho idea. Nota però che se devi passare solo un intero è inutile la malloc, in quanto viene passato per copia (guarda il mio esempio sui pthread).
Viene passato per copia? Allora lo rimetto come prima che funzionava...forse e' meglio ;)

Cimmo
05-11-2002, 13:48
Infatti non e' per quello...c'e' un bug da qualche parte che non dipende da quello...devo indagare :(

ilsensine
05-11-2002, 13:52
Benvenuto nel mondo delle race conditions :D

Cimmo
05-11-2002, 14:20
Originariamente inviato da ilsensine
[B]Benvenuto nel mondo delle race conditions :D
La cosa che fa piu' strippare e' che se fai partire il programma con le stesse identiche condizioni, delle volte il baco si presenta altre no. Sono gli effetti collaterali della concorrenza...se non sincronizzi bene tutto ti succede questo...ARGH! Ti scovero' bastardo dove sei...:mad:

cionci
05-11-2002, 15:44
Il problema magari avviene proprio perchè passi per indirizzo l'intero...se lo passi per valore non rischi che la lettura del valore avvenga dopo che il ciclo che lancia i thread l'abbia già modificato...
Nella concorrenza non può supporre l'ordine in cui le cose avvengono...quindi ti devi mettere sempre nel caso peggiore...

Cimmo
05-11-2002, 16:05
No il baco non e' li', si e' manifestato passandoglielo in enteambi i modi, e poi comunque la soluzione del sensine allocava memoria ogni volta e quindi non modificava mai la stessa variabile. Doveva andare per forza quella...
Adesso ho messo una cosina che sembra aver risolto, sembra perche' su 20 tentativi non si e' ancora manifestato, ma sono dubbioso sulla riuscita della cosa.

ilsensine
05-11-2002, 16:12
del sensine
killall -TERM Cimmo

Cimmo
05-11-2002, 16:31
Originariamente inviato da ilsensine
[B]
killall -TERM Cimmo
dovevo dire: de "ilsensine" scusa...ma che vuol dire?

Luc@s
05-11-2002, 16:38
Originariamente inviato da Cimmo
[B]
dovevo dire: de "ilsensine" scusa...ma che vuol dire?

kredo sia un comando *NIX che termina un processo:D

ilsensine
05-11-2002, 17:04
dovevo dire: de "ilsensine" scusa...ma che vuol dire?
Ilsensine? Oh niente, è una suprema entità che ti frigge il cervello se gli passi a qualche km di distanza :D
(è roba di D&D)

Luc@s
05-11-2002, 17:41
Una sola domanda: ma che progrmma hai creto e a cosa serve?

cionci
05-11-2002, 18:26
Originariamente inviato da Cimmo
[B]allocava memoria ogni volta e quindi non modificava mai la stessa variabile.

Secondo me è ancora più pericoloso... Pensa passando per valore il puntatore alla memoria allocata dinamicamente...
Il thread che è stato lanciato viene interrotto dopo la creazione...entra in esecuzione il thread principale che dealloca la memoria...il thread che è stato lanciato ritorna in esecuzione e legge il valore della memoria già deallocata ed il contenuto non è garantito :)

Allocando e deallocando presupponi che la lettura del valore avvenga prima della deallocazione...quindi hai fatto una supposizione sull'ordine di esecuzione dei thread e quindi sei già in errore...

Cimmo
05-11-2002, 18:31
Originariamente inviato da Luc@s
[B]Una sola domanda: ma che progrmma hai creto e a cosa serve?
In sintesi il problema e':
mandare un pacchetto ad uno o piu' destinazioni data una sorgente.
Il pacchetto deve essere segmentato per tutti gli host e caricata la rete a seconda della bandwith in modo che il pacchetto arrivi alle destinazioni nel modo piu' veloce possibile...(o almeno si spera :D)

Limiti a questa implementazione:
- tutti gli host sono collegati con la sorgente, ma non e' detto che tutti gli host siano collegati tra di loro
- la velocita' della rete (e di tutte le interconnessioni) e' nota alla sorgente
- il software non tiene conto delle dinamiche della rete, se mentre sta trasferendo una parte di rete si satura lui non ricalcola un altro tragitto.

Vi assicuro che non e' stato semplice...tra qualche giorno ve lo do da testare se ne avrete la voglia e il tempo...solo per Linux! :D

Cimmo
05-11-2002, 18:33
Originariamente inviato da cionci
[B]
Secondo me è ancora più pericoloso... Pensa passando per valore il puntatore alla memoria allocata dinamicamente...
Il thread che è stato lanciato viene interrotto dopo la creazione...entra in esecuzione il thread principale che dealloca la memoria...il thread che è stato lanciato ritorna in esecuzione e legge il valore della memoria già deallocata ed il contenuto non è garantito :)

Allocando e deallocando presupponi che la lettura del valore avvenga prima della deallocazione...quindi hai fatto una supposizione sull'ordine di esecuzione dei thread e quindi sei già in errore...
Se noti dall'esempio de "ilsensine" (:D) la deallocazione della struttura viene fatta dal thread figlio e non dal padre proprio per evitare questo side effect...

cionci
05-11-2002, 18:37
Originariamente inviato da Cimmo
[B]
Se noti dall'esempio de "ilsensine" (:D) la deallocazione della struttura viene fatta dal thread figlio e non dal padre proprio per evitare questo side effect...
Ah...non avevo visto :)

Luc@s
05-11-2002, 18:51
Originariamente inviato da Cimmo
[B]
In sintesi il problema e':
mandare un pacchetto ad uno o piu' destinazioni data una sorgente.
Il pacchetto deve essere segmentato per tutti gli host e caricata la rete a seconda della bandwith in modo che il pacchetto arrivi alle destinazioni nel modo piu' veloce possibile...(o almeno si spera :D)

Limiti a questa implementazione:
- tutti gli host sono collegati con la sorgente, ma non e' detto che tutti gli host siano collegati tra di loro
- la velocita' della rete (e di tutte le interconnessioni) e' nota alla sorgente
- il software non tiene conto delle dinamiche della rete, se mentre sta trasferendo una parte di rete si satura lui non ricalcola un altro tragitto.

Vi assicuro che non e' stato semplice...tra qualche giorno ve lo do da testare se ne avrete la voglia e il tempo...solo per Linux! :D

molto interessante!!!!!
Vuoi sapere come la memoria viene gestita dal kernel ???
Da bash digita:

memusage -p output.png -t -T <eseguibile>

cionci
05-11-2002, 18:58
Originariamente inviato da Cimmo
[B]Il pacchetto deve essere segmentato per tutti gli host
Che intendi con questo ?

Cimmo
05-11-2002, 19:09
Originariamente inviato da cionci
[B]
Che intendi con questo ?
Cioe' deve...la parola piu' giusta e': puo' segmentare.
Ti faccio un esempio:
abbiamo una sorgente S e 2 destinazioni D1 e D2
tra S e D1 c'e' una bandwith di 50 KB/s e cosi' anche tra S e D2.
Tra D1 e D2 invece c'e' una bandwith di 100 Kb/s.
Ora se spedisci normalmente 100 Kb a D1 e a D2 ci metti 2 secondi giusto? Piu' o meno chiaramente...
Se pero' mandi il 50% a D1 a 50 Kb/s e il restante 50% lo mandi a D2 sempre a 50 Kb/s e poi tra D1 e D2 si scambiano i rispettivi 50% usano meta' banda a testa e cosi' in (circa) 1 secondo si fa tutto.
Capito ora?

cionci
06-11-2002, 10:45
Cioè un classico problema di ottimizzazione...

Cimmo
06-11-2002, 11:37
Originariamente inviato da cionci
[B]Cioè un classico problema di ottimizzazione...
Diciamo di si'...

cionci
06-11-2002, 12:12
Comunque l'utilizzazione nel campo pratico è alquanto limitata...

Cimmo
06-11-2002, 16:28
Scusate dopo tante domande intelligenti una stupida: come si fa a cambiare colore di quello che stampi a video con la printf?

cionci
06-11-2002, 16:44
Con la printf non si fa...
Sotto Linux c'è la libreria ncurses che dovrebbe avere qualcosa in proposito...
Altrimenti giù di assembler ;) Anche se perdi al portabilità...

Cimmo
07-11-2002, 12:19
Toglietemi una curiosita':
ma se io faccio una malloc di una struttura e poi non faccio la free, al termine del programma la memoria torna disponibile oppure rimane occupata fino a quando non riavvio il pc?

cionci
07-11-2002, 14:21
Dovebbe tornare disponibile...almeno così succede in Windows...

Cimmo
18-11-2002, 12:43
Scusate un'altra cosa:
ma io se ho collegato un host con un altro, i due host possono spedirsi dei messaggi contemporaneamente usando la stessa connessione o devono farlo uno per volta?
Esempio A collegato con B:
A spedisce msg1 a B
B spedisce msg2 a A

il tutto contemporaneamente e usando la stessa connessione...si puo' fare? I messaggi vengono recapitati correttamente?

cionci
18-11-2002, 17:21
Certo che può avvenire in contemporanea !!!

Cimmo
19-11-2002, 00:10
Ok, ma perche' cavolo se A deve spedire a B e B non ha fatto una read prima della write di A .... B non riceve il messaggio? Cio' e' grave io come cavolo faccio a sapere se B e' in attesa oppure no?

cionci
19-11-2002, 10:46
Basta non fare le recv bloccanti ;)

Altrimenti con la select :

fd_set rTest;
TIMEVAL t;
FD_ZERO(&rTest);
FD_SET(recvSocket, &rTest);
rTest.fd_count = 1;
t.tv_sec = 1; //il timeout è di un secondo
t.tv_usec = 0;

if(select(0, &rTest, NULL, NULL, &t) != 1)
{
/*timeout*/
}
else
{
/*qui fai la receive*/
/*se la receive torna 0 byte allora errore*/
}

Cimmo
19-11-2002, 11:13
Originariamente inviato da cionci
[B]Basta non fare le recv bloccanti ;)
Ma io le ho fatte bloccanti, le ho fatte cosi':

int receiveData(int socketfd, char *msg)
{
int nread, n;

/* lettura */
nread=0;

while (1)
{
if ((n=read(socketfd, &(msg[nread]), MAXSIZE))<0)
{
if (errno!=EINTR)
{
char msgerror[1024];
sprintf(msgerror,"read() failed [err %d]",errno);
perror(msgerror);
fflush(stderr);
return(1);
}
}
else
{
if (n>0)
{
nread+=n;

if ((msg[nread-1]=='/') || (nread>=MAXSIZE))
break;
}
}
}

return(0);
};

cionci
19-11-2002, 11:18
Appunto NON le devi fare bloccanti !!!

La select serve per vedere se succede qualcosa su uno dei socket che si inseriscono con FD_SET...

Cimmo
19-11-2002, 11:26
Originariamente inviato da cionci
[B]Appunto NON le devi fare bloccanti !!!

La select serve per vedere se succede qualcosa su uno dei socket che si inseriscono con FD_SET...
Ah scusa avevo letto male...aspetta aspetta, io l'avevo studiata una volta la select, ma adesso non me la ricordo benissimo, serve per osservare gli eventi giusto?
La mia situazione e' questa: ho diversi socket su cui faccio tutte le mie read bloccanti...come faccio? Metto ogni volta nella variabile recvSocket il numero del socketfd su cui fare la read? E poi nel ramo else ci metto il mio codice?

cionci
19-11-2002, 11:33
Sì...recvSocket è il socket su cui devi ricevere i dati...

Altrimenti una cosa del genere :

fd_set rTest;
TIMEVAL t;
while(1)
{
FD_ZERO(&rTest);
FD_SET(recvSocket, &rTest);
rTest.fd_count = 1;
t.tv_sec = 0;
t.tv_usec = 100000; /*il timeout è di 100 ms*/

if(select(0, &rTest, NULL, NULL, &t) == 1)
{
/*qui fai la receive su recvSocket*/
/*se la receive torna 0 byte allora errore*/
}

if(ci sono dati da spedire)
faccio la send;

Faccio altre mie cosette;
}

Cimmo
19-11-2002, 11:40
Originariamente inviato da cionci
[B]Sì...recvSocket è il socket su cui devi ricevere i dati...

Ok provero'...ma se io ho solo da ricevere...non metto niente (neanche l'errore) e lui continua a loopare e poi appena gli arriva della roba tanto meglio...insomma una cosa del genere andrebbe bene?

int receiveData(int socketfd, char *msg)
{
int nread, n;
fd_set rTest;
TIMEVAL t;
nread=0;
while(1)
{
FD_ZERO(&rTest);
FD_SET(socketfd, &rTest);
rTest.fd_count = 1;
t.tv_sec = 0;
t.tv_usec = 100000; /*il timeout è di 100 ms*/
if(select(0, &rTest, NULL, NULL, &t) == 1)
{
if ((n=read(socketfd, &(msg[nread]), MAXSIZE))<0)
{
if (errno!=EINTR)
{
char msgerror[1024];
sprintf(msgerror,"read() failed [err %d]",errno);
perror(msgerror);
fflush(stderr);
return(1);
}
}
else
{
if (n>0)
{
nread+=n;

if ((msg[nread-1]=='/') || (nread>=MAXSIZE))
break;
}
}
}
}

Cimmo
20-11-2002, 10:05
Originariamente inviato da cionci
[B]
TIMEVAL t;

Ho dovuto mettere:
struct timeval t;
senno' non me lo prendeva...
[B]
rTest.fd_count = 1;

Dice:
host.c:1011: structure has no member named `fd_count'

....

cionci
20-11-2002, 11:12
Io l'ho fatto su Windows...guarda un po' se c'è un campo di nome simile...

Cimmo
20-11-2002, 11:32
Originariamente inviato da cionci
[B]Io l'ho fatto su Windows...guarda un po' se c'è un campo di nome simile...
Ho provato a vedere...adesso riguardo meglio...ma a cosa servirebbe?

Cimmo
20-11-2002, 11:37
In select.h c'e' questo:
typedef struct
{
/* XPG4.2 requires this member name. Otherwise avoid the name
from the global namespace. */
#ifdef __USE_XOPEN
__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
#else
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->__fds_bits)
#endif
} fd_set;

ilsensine
20-11-2002, 11:52
Sotto linux fd_set è diverso da windows, non puoi usare quel tag.

Cimmo
20-11-2002, 11:54
Originariamente inviato da ilsensine
[B]Sotto linux fd_set è diverso da windows, non puoi usare quel tag.
L'ho commentato...pero' non mi legge una cippa!
La funzione che ho messo e' identica all'ultimo post con codice che ho fatto senza ovviamente fd_set...

help!

cionci
20-11-2002, 11:58
Ma se non metti fd_set come fa a controllarti il socket ?

cionci
20-11-2002, 12:01
Se trovo gli esempio del mio prof con la select te li posto...

cionci
20-11-2002, 12:14
Guarda l'allegato...

ilsensine
20-11-2002, 12:51
Originariamente inviato da Cimmo
[B]
L'ho commentato...pero' non mi legge una cippa!
La funzione che ho messo e' identica all'ultimo post con codice che ho fatto senza ovviamente fd_set...

help!
Passa, come primo parametro della select, FD_SETSIZE (o il valore del socket su cui fare la select, se ce ne è solo uno).

Cimmo
20-11-2002, 13:53
Originariamente inviato da ilsensine
[B]
Passa, come primo parametro della select, FD_SETSIZE (o il valore del socket su cui fare la select, se ce ne è solo uno).
La richiamo cosi' la select:
select(socketfd, &rTest, NULL, NULL, &t)
dove socketfd e' il file descriptor del mio socket...ho piu' socket pero' per come ho progettato la cosa va bene anche far gestire alla select un socketfd alla volta anche se e' stupido lo so.
Pero' non funzia lo stesso...non legge niente.

Cimmo
20-11-2002, 14:44
Dunque funzia cosi':
nel codice c'era un if (come scritto all'inizio)
if(select(socketfd,&rTest,NULL,NULL,&t)==1)

pero' la select dovrebbe ritornare il valore del socketfd che ha ricevuto un evento (letto da man) quindi chi l'ha detto che sia 1? Cosi' ho provato a eguagliarlo al socketfd che mi interessa, ho provato a mettere >0 ma niente.
Facendo un po' debug ho visto che la select ritorna sempre 0 e che ci sono i valori di rTest (di tipo fd_set) sono tutti a 0. Adesso ho visto che campi ha (grazie al debug):
ha un campo che e' un array di 32 elementi chiamato fds_bits sara' per quello che non va'? Come devo metterlo?

cionci
20-11-2002, 14:48
E' diverso da quello di Windows che torna il numero di socket su cui sono avvenuti eventi...

Guarda l'esempio che ho allegato che è per FreeBSD...

Cimmo
20-11-2002, 15:25
L'ho visto l'esempio...penso di aver fatto bene le cose...
l'array di fd_set da quel che ho capito va' settato a 1 nell'elemento corrispondente al socketfd. E alla fine ho visto che lo fa...poi pero' non riceve niente...

ma perche' porco ca??o ????

E dire che ho letto anche l'esempio del man eccolo:

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int
main(void) {
fd_set rfds;
struct timeval tv;
int retval;

/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;

retval = select(1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */

if (retval)
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
else
printf("No data within five seconds.\n");

return 0;
}

Li' gli da' dentro 0 come socketfd perche' piglia dallo STDIN, pero' ho fatto identico io...AIUTOOOO!

Cimmo
20-11-2002, 16:21
Originariamente inviato da Cimmo
[B]L'ho visto l'esempio...penso di aver fatto bene le cose...
l'array di fd_set da quel che ho capito va' settato a 1 nell'elemento corrispondente al socketfd.
In verita' non e' proprio cosi'...pero' il codice che ho scritto dovrebbe andare bene eppure non funzia!
Qui ci vorrebbe Medioman :D
meglio se ilsensine...

cionci
20-11-2002, 16:51
Prova a partire da un esempio più semplice (sempre con i socket) e poi applicalo al tuo caso...

ilsensine
20-11-2002, 16:56
E' diverso da quello di Windows che torna il numero di socket su cui sono avvenuti eventi...

Sul valore di ritorno sia linux che windows seguono lo standard (ovvero il n. di fd sui quali è stato generato un evento, oppure 0 in caso di timeout, oppure -1 in caso di errore).

ilsensine
20-11-2002, 16:59
Li' gli da' dentro 0 come socketfd perche' piglia dallo STDIN, pero' ho fatto identico io...AIUTOOOO!
Oops come primo parametro della select devi passare l'fd del socket _più uno_.
Se fai la select su più socket passa l'fd più alto _più uno_ (oppure direttamente FD_SETSIZE)

Cimmo
21-11-2002, 09:50
Originariamente inviato da ilsensine
[B]
Oops come primo parametro della select devi passare l'fd del socket _più uno_.
Se fai la select su più socket passa l'fd più alto _più uno_ (oppure direttamente FD_SETSIZE)
Infatti ora funziona! :D
E dire che avevo appena tirato fuori un esempio del mio prof. e infatti c'era il +1...se l'avessi fatto subito ieri...vabbeh grazie...pero' sembra ancora perdersi della roba...
...ma per caso devo settare anche qualcosa a livello di socket? Tipo non bloccante quelle cose li'?

ilsensine
21-11-2002, 10:58
Se vuoi usare i socket non bloccanti, devi scriverti anche tutto il codice per gestire gli errori EAGAIN.
Io generalmente setto questa opzione sul server socket (va settata subito prima del bind):
int opt = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
Senza questa, può esserci un periodo più o meno lungo dopo uno shutdown non pulito durante il quale non puoi effettuare di nuovo il bind.

cionci
21-11-2002, 11:08
Originariamente inviato da ilsensine
[B]setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
La usa anche il mio prof...quindi va bene ;)
Il codice che ho postato prima è stato fatto da lui...
E' un testa incredibile...è stato citato nella licenza di Windows XP... Tra l'altro ha scritto parte del kernel di FreeBSD (il suo nome è presente anche in diversi man)...

Dovete vedere quando corregge le esercitazioni...

vi *.[ch]

e parte...10 secondi a file...è incredibile...e il bello è che ti chiede cose sul codice tipo : "come mai hai usato un unsigned int al posto di un unsigned char ?"

Cimmo
21-11-2002, 11:27
Originariamente inviato da ilsensine
[B]Se vuoi usare i socket non bloccanti, devi scriverti anche tutto il codice per gestire gli errori EAGAIN.
Io generalmente setto questa opzione sul server socket (va settata subito prima del bind):
int opt = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
Senza questa, può esserci un periodo più o meno lungo dopo uno shutdown non pulito durante il quale non puoi effettuare di nuovo il bind.
Ma quella opzione l'avevo gia' messa...io dico con la fcntl il flag O_NONBLOCK...cmq credo di avere problemi di sync...
insomma c'e' un msg di sync che non arriva a chi deve arrivare e dopo l'host non avendo la conferma a sua volta non inizia a spedire...

cionci
21-11-2002, 11:29
Originariamente inviato da Cimmo
[B]Ma quella opzione l'avevo gia' messa...io dico con la fcntl il flag O_NONBLOCK...cmq credo di avere problemi di sync...
insomma c'e' un msg di sync che non arriva a chi deve arrivare e dopo l'host non avendo la conferma a sua volta non inizia a spedire...
No...con la select non importa usare la recv non bloccante...

Cimmo
21-11-2002, 11:52
Sono in preda ad un crisi isterica se non risolvo questo problema strippo...la situazione e' questa:
A1 e A2 sono 2 figli di A e cosi' B1 e B2 sono 2 figli di B.
Cosa dovrebbe fare:

A1:
1) A1 cerca di connettersi con B2
2) una volta connesso spedisce il suo id a B2
3) Sblocca A2
4) si mette in attesa di READY da B2
5) spedisce dati a B2

A2:
1) Attende che A1 finisca le operazioni 1), 2) e 3)
2) Spedisce READY a B1
3) Riceve dati da B1

B1:
1) Attende che B2 finisca le operazioni 1), 2) e 3)
2) Attende READY da A2
3) Spedisce dati ad A2

B2:
1) Attende la connessione da A1
2) Riceve l'ID da A1
3) Sblocca B1
4) Spedisce READY a A1
5) Riceve dati da A1

Alla fine tutto funziona tranne che il READY spedito da A2 verso B1 non arriva e quindi lui non parte a spedire una bella cippa verso A2.

Perche'???