PDA

View Full Version : Utilizzo di semafori sotto linux


VegetaSSJ5
17-03-2004, 21:30
Salve a tutti, dovrei realizzare entro pochi giorni un programma che mi serve per l'università nel quale c'è bisogno che io faccia uso di semafori per sincronizzare dei processi. Questo programma deve essere sviluppato in ambiente linux. Ho cercato di documentarmi riguardo la creazione e l'utilizzo dei semafori e ho capito che per dichiarare dei semafori bisogna richiamare la funzione:

int semget(key_t key, int nsems, int flag)

Il mio dubbio riguarda il parametro key.
Non ho capito dove prenderlo e qual'è il suo scopo. Poichè è una questione urgente mi auguro che mi rispondiate al + presto, grazie.

ilsensine
18-03-2004, 09:04
E' un numero unico che identifica il semaforo (in generale un oggetto condiviso) nell'intero sistema.
Devi usare la stessa key nelle varie applicazioni per utilizzare lo stesso semaforo. Scegli tu un valore.

gabriele81
18-03-2004, 09:15
In pratica il tipo key_t è una ridefinizione del tipo int, devi assegnare tu un valore arbitrario al semaforo, che come ti ha detto ilsensine dovrai utilizzare nel tuo programma per riferirti a quel semaforo quando dovrai farci delle operazioni.
Infatti alla chiamata semop, che serve a cambiare il valore dei semafori, devi passargli quel valore per dirgli su quale semaforo operare. Ora non mi ricordo la sintassi, ma dovrebbe essere proprio il primo parametro.

ilsensine
18-03-2004, 09:35
Originariamente inviato da gabriele81
Infatti alla chiamata semop, che serve a cambiare il valore dei semafori, devi passargli quel valore per dirgli su quale semaforo operare.
No, credo che tutte le operazioni successive (semop, semctl...) vanno eseguite utilizzando il valore restituito da semget come handle.

gabriele81
18-03-2004, 09:58
Originariamente inviato da ilsensine
No, credo che tutte le operazioni successive (semop, semctl...) vanno eseguite utilizzando il valore restituito da semget come handle.


oooooooops....mi sa che hai ragione....volevo far vedere che ne sapevo qualcosa anche io ma ho cannato l'esempio...:muro:

VegetaSSJ5
18-03-2004, 14:10
ragazzi vi ringrazio. quindi e ho ben capito dovrei fare una cosa di questo genere:int mutex;
mutex=semget(0, 1, IPC_CREATE); /*creo l'insieme di semafori */giusto? ora però devo inizializzare il semaforo e devo usare la funzione semctl:


int semctl(int semid, int sem_num, int command, union semun ctl_arg);

ora se ho ben capito i primi due parametri sono rispettivamente il valore restituito da semget e la key che ho passato a semget, ma gli altri due parametri, cioè command e semnum, cosa sono e come li ottengo? io dovrei inizializzare il semaforo al valore 2 in modo tale che entrino nella sezione critica due processi alla volta, come devo fare? inoltre per effettuare le operazioni di wait e signal su questo semaforo come devo fare?
ragazzi vi ringrazio per la vostra disponibilità; rispondendomi mi state facendo un grossissimo favore, grazie!

ilsensine
18-03-2004, 14:16
Originariamente inviato da VegetaSSJ5
semget(0, 1, IPC_CREATE);
Vorresti cortesemente evitare per key dei valori riservati, possibilmente usati da altri o comunque sospetti? :D

Guarda caso, il valore "0" coincide con IPC_PRIVATE (v. man semget e /usr/include/bits/ipc.h ) :D

Hai a disposizione 2^32 valori, proprio 0 dovevi prendere? :D

gabriele81
18-03-2004, 14:23
Originariamente inviato da VegetaSSJ5
ragazzi vi ringrazio. quindi e ho ben capito dovrei fare una cosa di questo genere:int mutex;
mutex=semget(0, 1, IPC_CREATE); /*creo l'insieme di semafori */giusto? ora però devo inizializzare il semaforo e devo usare la funzione semctl:


int semctl(int semid, int sem_num, int command, union semun ctl_arg);

ora se ho ben capito i primi due parametri sono rispettivamente il valore restituito da semget e la key che ho passato a semget, ma gli altri due parametri, cioè command e semnum, cosa sono e come li ottengo? grazie ragazzi...


Stavolta mi sono documentato...:D

alla semctl devi passare nell'ordine:

- identificativo del semaforo (o meglio dell'array di semafori) restituito dalla semget

- numero del semaforo nell'array di semafori su cui eseguire l'operazione

- Tipo di comando

- parametri del comando

Quando tu chiami la semget come secondo parametro specifichi quanti semafori vuoi creare, e nella semctl devi indicare su quale operare (con 0 indichi il primo, con 1 il secondo ecc.). La key serve solo nell'invocazione della semget, poi ti serve l'handle restituita dalla funzione.

I tipi di comando possono essere questi (i più comuni):

- IPC_RMID: per eliminare l'array di semafori identificato da semid; gli altri parametri vengono ignorati

- GETALL: per leggere il valore di tutti i semafori nell'array, i valori vengono copiati in un buffer che il programmatore dovrà creare e passare alla funzione nel campo arg (l'ultimo).

- SETALL: setta i valori di tutti i semafori dell'array leggendo i valori da un buffer precedentemente impostato dal programmatore e passato come ultimo parametro.

- GETVAL: la funzione restituisce il valore del semaforo specificato dal numero passato come secondo argomento, l'ultimo parametro viene ignorato

- SETVAL: imposta il valore del semaforo specificato da sem_num uguale al valore passato come ultimo parametro.

VegetaSSJ5
18-03-2004, 19:46
Originariamente inviato da gabriele81
Stavolta mi sono documentato...:D

alla semctl devi passare nell'ordine:

- identificativo del semaforo (o meglio dell'array di semafori) restituito dalla semget

- numero del semaforo nell'array di semafori su cui eseguire l'operazione

- Tipo di comando

- parametri del comando

Quando tu chiami la semget come secondo parametro specifichi quanti semafori vuoi creare, e nella semctl devi indicare su quale operare (con 0 indichi il primo, con 1 il secondo ecc.). La key serve solo nell'invocazione della semget, poi ti serve l'handle restituita dalla funzione.

I tipi di comando possono essere questi (i più comuni):

- IPC_RMID: per eliminare l'array di semafori identificato da semid; gli altri parametri vengono ignorati

- GETALL: per leggere il valore di tutti i semafori nell'array, i valori vengono copiati in un buffer che il programmatore dovrà creare e passare alla funzione nel campo arg (l'ultimo).

- SETALL: setta i valori di tutti i semafori dell'array leggendo i valori da un buffer precedentemente impostato dal programmatore e passato come ultimo parametro.

- GETVAL: la funzione restituisce il valore del semaforo specificato dal numero passato come secondo argomento, l'ultimo parametro viene ignorato

- SETVAL: imposta il valore del semaforo specificato da sem_num uguale al valore passato come ultimo parametro.
grazie ragazzi!

x ilsensine
mamma mia che sfortuna che ho! proprio quello ho beccato....;) ;) vabbè vorrà dire che metterò come valore 1367, spero non corrisponda a nulla in particolare...:)

x gabriele81
ti ringrazio molto ora è tutto più chiaro. dunque dovrei fare così:int mutex;
mutex=semget(1367, 1, IPC_CREATE); /*creo l'insieme di semafori */
semctl(mutex, 0, SETVAL, 2); /*inizializzo a due l'unico semaforo che ho creato semaforo */ragazzi un'ultima cosa: la semctl restituisce un intero, cioè cosa? grazie 2^20 :sofico: :sofico: :)

gabriele81
19-03-2004, 08:21
Originariamente inviato da VegetaSSJ5
ti ringrazio molto ora è tutto più chiaro. dunque dovrei fare così:int mutex;
mutex=semget(1367, 1, IPC_CREATE); /*creo l'insieme di semafori */
semctl(mutex, 0, SETVAL, 2); /*inizializzo a due l'unico semaforo che ho creato semaforo */ragazzi un'ultima cosa: la semctl restituisce un intero, cioè cosa? grazie 2^20 :sofico: :sofico: :)

Il codice mi sembra giusto, solo una cosa: di solito i mutex hanno valore 0 o 1, se lo inizializzi a 2 dagli un altro nome, giusto per non confondere le idee ;)

La semctl restituisce -1 in caso di errore, oppure il valore del semaforo specificato se come comando hai messo GETVAL, negli altri casi un valore positivo. Quando la invochi ti conviene fare un check sul valore restituito, se è < 0 lanci un errore (o un segnale o quello che ti fa più comodo).

VegetaSSJ5
19-03-2004, 10:48
perfetto. ragazzi grazie a tutti, cmq credo in questi giorni di avere di nuovo bisogno di voi per cui occhio a questo thread. ciao!

VegetaSSJ5
19-03-2004, 14:34
ragazzi come non detto, rieccomi qua. dunque spiegamo il problema: io devo creare 2*N (con N dato in input) processi e li devo mettere in attesa ad un semaforo. io ho scritto questo, ma non so come devo usare semop(...) per effettuare le wait e le signal:void genera_giocatori (int N) {
pid_t giocatori[2*N];
int i=0;
int AccessoAlTavolo;
AccessoAlTavolo=semget(200, 1, IPC_CREAT);
semctl(AccessoAlTavolo, 0, SETVAL, 0);
for (i=0; i<2*N; ++i) {
pid_t pid= fork();
if (pid!=0) giocatori[i]=pid;
else if (pid==0) WAIT SEMAFORO ACCESSO AL TAVOLO;
else {
perror("Si è verificato un errore durante la creazione dei processi giocatori");
exit(1);
}
}
} in praticami creo un array dove metto i pid dei processi che ho generato, creo ed inizializzo il semaforo AccessoAlTavolo a 0 (in modo tale che nessun processo appena che io faccia la wait sul semaforo di quel processo mi entri nella sezione critica), faccio una wait al processo appena creato sul semaforo. il problema è: come si usa semop per fare la wait (e la signal)?

inoltre ho un'altra domanda: data l'istruzionepid_t aaa;
aaa=fork(); il processo padre ha in aaa il valore del pid del processo generato. il processo generato (figlio) ha in aaa il valore 0, giusto? ma allora se faccio cosìpid_t arbitro;
arbitro=fork();
if (arbitro==0) genera_giocatori(n);quando eseguo il programma, il processo arbitro che ho creato dovrebbe eseguirmi la fork (perchè il processo arbitro ha in arbitro il valore 0 e quindi entra nell'if) invece non lo fa, come mai???

Tortellone
19-03-2004, 15:44
Originariamente inviato da ilsensine
Vorresti cortesemente evitare per key dei valori riservati, possibilmente usati da altri o comunque sospetti? :D

Guarda caso, il valore "0" coincide con IPC_PRIVATE (v. man semget e /usr/include/bits/ipc.h ) :D

Hai a disposizione 2^32 valori, proprio 0 dovevi prendere? :D


Rotfl mi ha fatto divertire molto questo intervento :D


:sofico:

VegetaSSJ5
25-03-2004, 13:27
ragazzi il problema precedente è stato risolto, ma ora ho bisogno di nuovo di una vostra piccola mano:
allora, ci sono dei processi giocatori che giocano a due a due e poi alla fine della partita si mettono in pausa con la funzione pause(). Poi c'è il processo arbitro che deve fare dei conti e poi prendere i due processi che hanno ottenuto il punteggio migliore. Ho individuato tali processi e ho ucciso gli altri con kill(PID, SIGKILL), a questo punto dovrei svegliare i due processi che hanno ottenuto punteggio migliore e portarli ad una funzione seconda_fase(). Come faccio a svegliare questi processi e a portarli alla funzione seconda_fase()?

cn73
25-03-2004, 14:54
[EDIT]

VegetaSSJ5
25-03-2004, 19:14
Originariamente inviato da cn73
[EDIT]
:confused:

ilsensine
26-03-2004, 08:02
Originariamente inviato da VegetaSSJ5
ragazzi il problema precedente è stato risolto, ma ora ho bisogno di nuovo di una vostra piccola mano:
allora, ci sono dei processi giocatori che giocano a due a due e poi alla fine della partita si mettono in pausa con la funzione pause(). Poi c'è il processo arbitro che deve fare dei conti e poi prendere i due processi che hanno ottenuto il punteggio migliore. Ho individuato tali processi e ho ucciso gli altri con kill(PID, SIGKILL), a questo punto dovrei svegliare i due processi che hanno ottenuto punteggio migliore e portarli ad una funzione seconda_fase(). Come faccio a svegliare questi processi e a portarli alla funzione seconda_fase()?
Semplicemente, manda un segnale a tua scelta (ad es. SIGUSR1) ai processi da svegliare.
Normalmente SIGUSR1 causa la terminazione del processo, a meno che non gli assegni una funzione per gestirlo.
v. man signal (o sigaction) per informazioni su come assegnare un handler a un segnale. A te basta una funzione vuota, che evita la terminazione del processo.

cn73
26-03-2004, 09:37
Originariamente inviato da VegetaSSJ5
:confused:

Mi ero accorto di avere detto una castronata :D

VegetaSSJ5
26-03-2004, 10:41
Originariamente inviato da ilsensine
Semplicemente, manda un segnale a tua scelta (ad es. SIGUSR1) ai processi da svegliare.
Normalmente SIGUSR1 causa la terminazione del processo, a meno che non gli assegni una funzione per gestirlo.
v. man signal (o sigaction) per informazioni su come assegnare un handler a un segnale. A te basta una funzione vuota, che evita la terminazione del processo.
ti ringrazio anche se avevo risolto da solo. ho mandato il segnale SIGINT. scusa ma se io il segnale noon lo gestisco, cioè non creo una funzione per gestire sigint, il processo termina? nel caso dovessi creare comunque questa funzione, non potresti scrivermela tu? tieni conto che i processi che devo svegliare sono in pausa...

ilsensine
26-03-2004, 10:56
Originariamente inviato da VegetaSSJ5
scusa ma se io il segnale noon lo gestisco, cioè non creo una funzione per gestire sigint, il processo termina?
Normalmente sì. Non so se sigint è ignorato di default.

nel caso dovessi creare comunque questa funzione, non potresti scrivermela tu? tieni conto che i processi che devo svegliare sono in pausa...
Così è come farei io:

#include <signal.h>
#include <unistd.h>

int last_signal = 0;

void null_sighandler(int signum) {
last_signal = signum;
signal(signum, null_sighandler);
}

void do_pause() {
while(last_signal!=SIGUSR1)
pause();
last_signal = 0;
}

int main() {
signal(SIGUSR1, null_sighandler);
(...)
do_pause();
}

VegetaSSJ5
26-03-2004, 11:24
Originariamente inviato da ilsensine
Normalmente sì. Non so se sigint è ignorato di default.


Così è come farei io:

#include <signal.h>
#include <unistd.h>

int last_signal = 0;

void null_sighandler(int signum) {
last_signal = signum;
signal(signum, null_sighandler);
}

void do_pause() {
while(last_signal!=SIGUSR1)
pause();
last_signal = 0;
}

int main() {
signal(SIGUSR1, null_sighandler);
(...)
do_pause();
}

ti ringrazio, ma potresti spiegarmi cosa fanno (come funzionano) queste funzioni?

ilsensine
26-03-2004, 11:28
"signal" assegna un handler a un segnale. Lo ripeto anche nell'handler in quanto non ho capito bene dalla documentazione se l'handler viene resettato dopo il segnale o meno.
do_pause è una variante di pause, ma controlla se il segnale è arrivato _prima_ di mettersi in attesa (potrebbe causare un deadlock).

VegetaSSJ5
26-03-2004, 11:44
Originariamente inviato da ilsensine
"signal" assegna un handler a un segnale. Lo ripeto anche nell'handler in quanto non ho capito bene dalla documentazione se l'handler viene resettato dopo il segnale o meno.
do_pause è una variante di pause, ma controlla se il segnale è arrivato _prima_ di mettersi in attesa (potrebbe causare un deadlock).
grazie 1000