Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Polestar 3 Performance, test drive: comodità e potenza possono convivere
Polestar 3 Performance, test drive: comodità e potenza possono convivere
Abbiamo passato diversi giorni alla guida di Polestar 3, usata in tutti i contesti. Come auto di tutti i giorni è comodissima, ma se si libera tutta la potenza è stupefacente
Qualcomm Snapdragon X2 Elite: l'architettura del SoC per i notebook del 2026
Qualcomm Snapdragon X2 Elite: l'architettura del SoC per i notebook del 2026
In occasione del proprio Architecture Deep Dive 2025 Qualcomm ha mostrato in dettaglio l'architettura della propria prossima generazione di SoC destinati ai notebook Windows for ARM di prossima generazione. Snapdragon X2 Elite si candida, con sistemi in commercio nella prima metà del 2026, a portare nuove soluzioni nel mondo dei notebook sottili con grande autonomia
Recensione DJI Mini 5 Pro: il drone C0 ultra-leggero con sensore da 1 pollice
Recensione DJI Mini 5 Pro: il drone C0 ultra-leggero con sensore da 1 pollice
DJI Mini 5 Pro porta nella serie Mini il primo sensore CMOS da 1 pollice, unendo qualità d'immagine professionale alla portabilità estrema tipica di tutti i prodotti della famiglia. È un drone C0, quindi in un peso estremamente contenuto e che non richiede patentino, propone un gimbal rotabile a 225 gradi, rilevamento ostacoli anche notturno e autonomia fino a 36 minuti. Caratteristiche che rendono il nuovo drone un riferimento per creator e appassionati
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 05-03-2008, 17:28   #1
f.bandiera
Member
 
Iscritto dal: Apr 2007
Messaggi: 51
[C] soluzione al problema lettori/scrittori con mutex e variabili condizionali

Ciao a tutti, devo scrivere codice C che usando mutex e variabli condizionali, mi porti a risolvere il problema dei lettori/scrittori....

Qualcuno saprebbe indicarmi dove reperire delle informazioni du questo classico problema di sincronizzazione di processi concorrenti?

Sto cercando ma ancora non ho trovato niente che non usi i semafori.....

Grazie
f.bandiera è offline   Rispondi citando il messaggio o parte di esso
Old 06-03-2008, 06:19   #2
f.bandiera
Member
 
Iscritto dal: Apr 2007
Messaggi: 51
Nessuno sa indicarmi anche solo la spiegazione del problema?
possibilmente in italiano?

il problema "lettori-scrittori" con precedenza agli scrittori dovrebbe essere conosciuto, tutti ne parlano come di un classico problema di sincronizzazione, ma nessuno scrive di più o spiega come funziona.... o almeno io non l'ho trovato!
Nessuno ne sa niente?

Aiutatemi, per favore....
Grazie
f.bandiera è offline   Rispondi citando il messaggio o parte di esso
Old 06-03-2008, 07:55   #3
jgvnn
Senior Member
 
L'Avatar di jgvnn
 
Iscritto dal: Mar 2002
Città: Provincia di Varese
Messaggi: 5096
Quote:
Originariamente inviato da f.bandiera Guarda i messaggi
Nessuno sa indicarmi anche solo la spiegazione del problema?
possibilmente in italiano?

il problema "lettori-scrittori" con precedenza agli scrittori dovrebbe essere conosciuto, tutti ne parlano come di un classico problema di sincronizzazione, ma nessuno scrive di più o spiega come funziona.... o almeno io non l'ho trovato!
Nessuno ne sa niente?

Aiutatemi, per favore....
Grazie
Ciao, sì il problema dei mutex read-write è conosciuto, tuttavia ricorda che un mutex read-write è più costoso di un mutex semplice, e spesso è più conveniente usare mutex semplici se si può ridurre il tempo di lock (cioè tenere la risorsa occupata x il minor tempo possibile).
Di link su google se imposti "mutex read write" ne trovi diversi, adesso non te ne linko uno perché non mi piacerebbe indicartene uno sostanzialmente a caso.
Se hai bisogno di qualche info in più contattami pure!
jgvnn è offline   Rispondi citando il messaggio o parte di esso
Old 06-03-2008, 10:45   #4
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
E' un classico problema di passaggio del testimone.
Dopo che uno qualsiasi dei thread di lettura e scrittura ha terminato la sua operazione, fai in modo che controlli se c'è almeno uno scrittore bloccato in attesa su una mutex (una condition in realtà) venga risvegliato uno di questi scrittori.
Inoltre, se non ci sono scrittori in attesa, ma ci sono sono lettori in attesa si sveglia un lettore.

E' importante in questi casi che un thread risvegli solamente un altro thread, di fatto gestisci in questo modo la mutua esclusione.
E' chiaro che ci sarà starvation per i lettori.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 06-03-2008, 15:35   #5
tæo
Member
 
L'Avatar di tæo
 
Iscritto dal: Sep 2005
Messaggi: 82
non è passato molto tempo da quando anche io mi sono interessato alla questione

se ti può servire, ecco un listato del problema produttore-consumatore (altro modo per chiamare scrittore-lettore). fa uso di un monitor con un mutex e due variabili condizionali

essenzialmente il processo fa partire due thread (oltre al main), chiamati rispettivamente produttore (scrittore) e consumatore (lettore). entrambi devono accedere ad una stessa area di memoria (il così chiamato buffer di dimensione 16) protetto da un mutex per garantire la mutua esclusione. il senso del giovo è garantire la corretta interazione tra chi riempie il buffer (il produttore) e chi lo consuma impedendo comportamenti scorretti quali la lettura di un buffer vuoto e l'inserimento in un buffer pieno. nelle situazioni intermedie invece entrano in gioco le variabili condizionali che permettono il risveglio di determinati thread in attesa di un certo evento. ad esempio quando il buffer è vuoto il lettore non può ovviamente leggere il contenuto e si mette quindi in attesa che lo scrittore compia l'operazione di inserimento.


Codice:
#include <stdio.h>
#include <pthread.h>

#define OVER -1
#define max 100
#define BUFFER_SIZE 16 

typedef struct {
	int buffer[BUFFER_SIZE]; 
	pthread_mutex_t lock; 
	int readpos, writepos; 
	int buffer_count; 
	pthread_cond_t buffer_empty; 
	pthread_cond_t buffer_full; 
} prodcons;

prodcons buffer; 
int go;

/* Inizializza il buffer */ 
void init(prodcons *b) { 
	pthread_mutex_init (&b->lock, NULL); 
	pthread_cond_init (&b->buffer_empty, NULL); 
	pthread_cond_init (&b->buffer_full, NULL); 
	b->buffer_count=0; 
	b->readpos = 0; 
	b->writepos = 0; 
} 

/* Inserimento: */ 
void inserisci(prodcons *b, int data) {
	pthread_mutex_lock (&b->lock); 
	
	/* mentre il buffer è pieno sospendo l'inserimento */ 
	while(b->buffer_count==BUFFER_SIZE) 
		pthread_cond_wait (&b->buffer_full, &b->lock); 
		
	/* scrivi data e aggiorna lo stato del buffer */ 
	b->buffer[b->writepos] = data; 
	b->buffer_count++; 
	b->writepos++; 
	if(b->writepos >= BUFFER_SIZE) 
		b->writepos = 0; 
	
	/* risveglia eventuali thread (consumatori) sospesi all'empty */ 
	pthread_cond_signal(&b->buffer_empty); 
	pthread_mutex_unlock(&b->lock); 
} 

/*ESTRAZIONE:  */ 
int estrai(prodcons *b) {
	int data; 
	pthread_mutex_lock (&b->lock); 
	
	/* mentre il buffer è vuoto sospendo l'estrazione */
	while(b->buffer_count==0)
		pthread_cond_wait (&b->buffer_empty, &b->lock); 
	
	/* leggi data e aggiorna lo stato del buffer*/ 
	data = b->buffer[b->readpos]; 
	b->buffer_count--; 
	b->readpos++; 
	if(b->readpos >= BUFFER_SIZE) 
		b->readpos = 0; 
	
	/* risveglia eventuali thread (produttori) sospesi al full*/ 
	pthread_cond_signal(&b->buffer_full); 
	pthread_mutex_unlock(&b->lock); 
	return data; 
}

void *producer (void *data) {
	int n;
	for (n = 0; n<go; n++) {
		printf("\tproduttore ---> %d\n", n); 
		inserisci(&buffer, n); 
	} 
	inserisci(&buffer, OVER); 
	return (void*) 0; 
} 

void *consumer (void *data) {
	int d = 0;
	while(d != OVER) {
		d = estrai(&buffer);
		printf("consumatore <-- %d\n", d); 
	} 
	return (void*) 0; 
} 

int main(int argc, char* argv[]) { 
	pthread_t th_a, th_b; 
	void *retval; 
	init(&buffer);
	
	if(argc<2)
		go = max;
	else
		go = atoi(argv[argc-1]);
	
	/* creazione thread */ 
	pthread_create(&th_a, NULL, producer, 0); 
	pthread_create(&th_b, NULL, consumer, 0); 
	
	/* attesa teminazione threads creati: */ 
	pthread_join(th_a, &retval); 
	pthread_join(th_b, &retval); 
	
	//printf("%d", (int*)retval); 
	
	return 0; 
}
è adeguatamente commentato, se conosci la libreria pthread e il funzionamento delle primitive di mutua esclusione/sincronizzazione, il codice dovrebbe essere comprensibile
__________________
Saigon, shit. I'm still only in Saigon.

Ultima modifica di tæo : 06-03-2008 alle 15:40.
tæo è offline   Rispondi citando il messaggio o parte di esso
Old 06-03-2008, 15:47   #6
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Non è la stessa cosa, l'accesso alla risorsa condivisa (un buffer) è garantito dai semafori pieno/vuoto perché la risorsa condivisa è multipla (al contrario nel problema sopra poteva anche essere una sola), inoltre non c'è alcuna precedenza agli scrittori rispetto ai lettori.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 06-03-2008, 16:13   #7
tæo
Member
 
L'Avatar di tæo
 
Iscritto dal: Sep 2005
Messaggi: 82
hai ragione, mi sono perso la chiosa sulla precedenza agli scrittori. ma d'altra parte, come ho detto, il listato fa parte di una mia vecchia collezione di sorgenti che avevo provato per imparare le basi della programmazione concorrente. leggendo il titolo del thread mi sono sentito di proporre il risultato, sperando che possa essergli d'aiuto come ispirazione e primo assaggio del problema ma non come una sua soluzione


in ogni caso non ho capito cosa intendi quando parli di semafori.
__________________
Saigon, shit. I'm still only in Saigon.
tæo è offline   Rispondi citando il messaggio o parte di esso
Old 06-03-2008, 18:31   #8
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Quote:
Originariamente inviato da tæo Guarda i messaggi
in ogni caso non ho capito cosa intendi quando parli di semafori.
Queste due variabili:

pthread_cond_t buffer_empty;
pthread_cond_t buffer_full;

più i rispettivi contatori svolgono una funzione identica a quella delle primitive semaforiche, solo che nei semafori i contatori sono racchiusi all'interno delle primitive.
Cioè è la classica rappresentazione di una coda circolare in ambiente a multithreading.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 06-03-2008, 19:00   #9
tæo
Member
 
L'Avatar di tæo
 
Iscritto dal: Sep 2005
Messaggi: 82
ok, ora è chiaro

in effetti anche il mutex non è altro che un semaforo (binario), alla fine si ritorna sempre lì

cmq grazie per la precisazione
__________________
Saigon, shit. I'm still only in Saigon.
tæo è offline   Rispondi citando il messaggio o parte di esso
Old 07-03-2008, 21:50   #10
f.bandiera
Member
 
Iscritto dal: Apr 2007
Messaggi: 51
Ciao a tutti!
Allora, ho cercato di studiare il problema e di implementare un mio rwlock personale ma.... ci sono andato solo vicino......

Il fatto è che secondo me le funzioni scritte per gestire l'RWLock vanno bene, mi sembrano pure ben fatte! purtroppo una volta applicate hanno un funzionamento alternato (cioè ogni tanto vanno e fanno il loro lavoro, molto più spesso NO ).

A questo punto chiedo l'aiuto di qualunque buonanima voglia mettersi alla prova con un buon debug o con dei consigli, perchè io sto esaurendo le idee.
Posto il codice del mio RW Lock applicato al programma che ci è stato dato per testarlo....

file list.c
Codice:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "linkedlist.h"

#define YES 1
#define NO 0

typedef char bool;
typedef struct thread_rwlock thread_rwlock_t;
typedef thread_rwlock_t * to_rwl;

struct thread_rwlock {
	pthread_mutex_t     guardia;        /* controllo di accesso */ 
	pthread_cond_t      canread;        /* posso leggere? */
	pthread_cond_t      canwrite;       /* posso scrivere? */
	int                 r_run;          /* lettori attualmente attivi */
	int                 w_run   ;       /* scrittori attualmente attivi */
	int                 r_wait;         /* lettori che aspettano */
	int                 w_wait;         /* scrittori che aspettano */
        bool                to_use;         /* controllo errori */
};

int thread_rwlock_init ( to_rwl );		
int thread_rwlock_destroy ( to_rwl );
int thread_rwlock_rdlock ( to_rwl );
void thread_rwlock_tryrdlock ( to_rwl );
int thread_rwlock_wrlock ( to_rwl );
void thread_rwlock_trywrlock ( to_rwl );
int thread_rwlock_rdunlock ( to_rwl );
int thread_rwlock_wrunlock ( to_rwl );


thread_rwlock_t RWL;


int main(int argc, char *argv[])
{

  int i;
  pthread_t *f_tid;
  pthread_t *e_tid;
  lista_impiegati.next = NULL;
  lista_impiegati.nome = (char *)-1;

  if(argc >= 2) TRASFER_DELAY  = atoi(argv[1]);
  if(argc >= 3) AUMENTO_DELAY  = atoi(argv[2]);
  if(argc >= 4) N_IMPIEGATI    = atoi(argv[3]);
  if(argc >= 5) N_AUMENTI      = atoi(argv[4]);
  if(argc >= 6) E_THREADS      = atoi(argv[5]);
  if(argc >= 7) F_THREADS      = atoi(argv[6]);

thread_rwlock_init ( &RWL );

  f_tid = (pthread_t *)malloc(sizeof(pthread_t)*F_THREADS);
  e_tid = (pthread_t *)malloc(sizeof(pthread_t)*E_THREADS);

  printf(" TRASFER_DELAY: %d\n AUMENTO_DELAY: %d\n N_IMPIEGATI: %d\n N_AUMENTI: %d\n E_THREADS: %d\n F_THREADS: %d\n",\
	 TRASFER_DELAY,AUMENTO_DELAY,N_IMPIEGATI,N_AUMENTI,E_THREADS,F_THREADS);

  /* crea la lista degli impiegati */
  crea_lista_impiegati();
  
  for(i = 0;i < F_THREADS;i++)
    pthread_create(&f_tid[i],NULL,da_aumento_lista_impiegati,crea_lista_aumenti(i*10));

  for( i = 0;i < E_THREADS;i++)
    pthread_create(&e_tid[i],NULL,trasferisci_lista_impiegati,crea_lista_trasfer(i));		    

  
  for(i = 0; i < F_THREADS;i++)
    pthread_join(f_tid[i],NULL);

  for(i = 0; i < E_THREADS;i++)
    pthread_join(e_tid[i],NULL);

  conta_trovati(-1);
  conta_conflitti(-1);


thread_rwlock_destroy ( &RWL );


  printf("Fatto\n");

  exit(0);
}

void conta_conflitti(int i)
{
  static int count = 0,max_count = 0;
  static pthread_mutex_t conta_lock = PTHREAD_MUTEX_INITIALIZER;

  pthread_mutex_lock(&conta_lock);
  count += i;
  if( i == -1 ) printf("Conflitti: %d\n",max_count);

  if( count > max_count )
    max_count = count;
  pthread_mutex_unlock(&conta_lock);
}

void conta_trovati(int i)
{
  static int count = 0, max_count = 0;
  static pthread_mutex_t conta_lock = PTHREAD_MUTEX_INITIALIZER;
  
  pthread_mutex_lock(&conta_lock);
  count += i;
  if( i == -1 ) printf("Totale trasferimenti + aumenti : %d\n",max_count); 
  if( count > max_count )
    max_count = count;
  pthread_mutex_unlock(&conta_lock);
}

void stampa_lista_impiegati(impiegato_t *p)
{
  int i = 0;

  while( p != NULL ) {
    printf("(%s %d) ",p->nome,p->salario);
    p = p->next;
    i++;
    if( (i % 5) == 0 ) printf("\n");
  }
}

impiegato_t *trova_impiegato(char *nome)
{
  impiegato_t *p = &lista_impiegati;
  impiegato_t *p1;

  p1 = p->next;
  while(p1 != NULL) {
    if( strcmp(p1->nome,nome) == 0 )
      {
	conta_trovati(1);
	return(p);
      }
    p = p1;
    p1 = p->next;
  }
  return(NULL);
}

void crea_lista_impiegati()
{
  int i;
  char s[20], *s1;

  for(i = 0; i < N_IMPIEGATI;i++) {
    sprintf(s,"Jan_%d",i);
    s1 = (char *)malloc(strlen(s)+1);
    strcpy(s1,s);
    aggiungi_lista_impiegati(s1);
  }
}

void aggiungi_lista_impiegati(char *nome)
{
  impiegato_t *p;
  
  p = (impiegato_t *)malloc(sizeof(impiegato_t));
  p->nome = nome;
  p->salario = 0;
  p->next = lista_impiegati.next;
  lista_impiegati.next = p;
}

void da_aumento_impiegato(impiegato_t *p)
{
  if( p == NULL ) return;
  
  p->next->salario++;
  delay(AUMENTO_DELAY,0);
}

void *da_aumento_lista_impiegati(void *arg) 
{
  impiegato_t *p;
  impiegato_t *lista = (impiegato_t *)arg;

  while( lista != NULL ) {

thread_rwlock_rdlock ( &RWL );

    p = trova_impiegato(lista->nome);
    da_aumento_impiegato(p);
    lista = lista->next;

thread_rwlock_rdunlock ( &RWL );

    delay(0,0);
  }
  return NULL;
}

impiegato_t *crea_lista_aumenti(int seed1)
{
  int i,r;
  unsigned int seed = (int)seed1;
  char s[20],*s1;
  impiegato_t *p,lista;

  lista.next = NULL;
  
  for( i = 0; i < N_AUMENTI; i++ ) {
    r = rand_r(&seed) % N_IMPIEGATI;
    sprintf(s,"Jan_%d",r);
    s1 = (char *)malloc(strlen(s)+1);
    strcpy(s1,s);
    p = (impiegato_t *)malloc(sizeof(impiegato_t));
    p->nome = s1;
    p->next = lista.next;
    lista.next = p;
  }
  return(lista.next);
}

void trasferisci_impiegato(impiegato_t *p)
{
  impiegato_t *p1;

  p1 = p->next;
  p->next = p1->next;

  printf("Trasferimento: (%s %d)\n",p1->nome,p1->salario);
  free(p1->nome);
  free(p1);
  delay(TRASFER_DELAY,0);
  return;
}

void *trasferisci_lista_impiegati(void *arg)
{
  impiegato_t *p;
  impiegato_t *lista = (impiegato_t *)arg;

  while(lista != NULL ) {

thread_rwlock_wrlock ( &RWL );

    p = trova_impiegato(lista->nome);
    if (p) trasferisci_impiegato(p);
    lista = lista->next;

thread_rwlock_wrunlock ( &RWL );

    delay(0,0);
  }
  return NULL;
}

impiegato_t *crea_lista_trasfer(int s)
{
  return(crea_lista_aumenti(s));
}

void delay(int sleep_ms,int cpu_us)
{
  int i, cicli = cpu_us * 8;
  volatile int j;
  struct timespec tv;

  if( sleep_ms != 0) {
    tv.tv_sec = sleep_ms/1000;
    tv.tv_nsec = (sleep_ms % 1000)*1000000;
    nanosleep(&tv,NULL);
  }

  if( cpu_us != 0 )
    for( i = 0; i < cicli; i++) j++;
}





/* RW-Lock function */

int thread_rwlock_init ( to_rwl rwl )
{
	int ok;				/* controllo errori */
	rwl->r_run = 0;
	rwl->w_run = 0;
	rwl->r_wait = 0;
	rwl->w_wait = 0;
	
	ok = pthread_mutex_init ( &rwl->guardia, NULL );
	if ( ok ) 
		{
			/* se fallisce la creazione ritorno un errore */
			printf ("\nErrore inizializzazione mutex\n");
			return ok;
		}

	ok = pthread_cond_init ( &rwl->canread, NULL );
	if ( ok ) 
		{
			/* se fallisce la creazione distruggo il mutex e ritorno un errore */
			printf ("\nErrore inizializzazione variabile (I can read ?)\n");
			pthread_mutex_destroy ( &rwl->guardia );
			return ok;
		}

	ok = pthread_cond_init ( &rwl->canwrite, NULL );
	if ( ok ) 
		{
			/* se fallisce la creazione distruggo il mutex e la precedente variabile condizionale e ritorno un errore */
			printf ("\nErrore inizializzazione variabile (I can read ?)\n");
			pthread_mutex_destroy ( &rwl->guardia );
			pthread_cond_destroy ( &rwl->canread );
			return ok;
		}
    
	rwl->to_use = YES;    
	return 0;
}

int thread_rwlock_destroy ( to_rwl rwl )
{
	int ok;
	/* check validità dell'RW-Lock, mi serve per escludere eventuali usi futuri di una struct thread_rwlock in fase di deallocazione */
	if ( !rwl->to_use )
		{
			printf ("\nL'RW-Lock e' corrotto!!!\n");
			return -1;		
		}
	/* provo a prendere possesso dell'RW-Lock */
	ok = pthread_mutex_trylock ( &rwl->guardia );
	if ( ok )
		{
			printf ("\nL'RW-Lock è occupato, impossibile accedere\n");
			return ok;
		}
	/* se arrivo a questo punto la guardia è locked, controllo se ci sono threads attive */
	if ( rwl->r_run || rwl->w_run )
		{
			printf ("\nCi sono ancora thread attive, non posso distruggere l'RW-Lock\n");
			ok = pthread_mutex_unlock ( &rwl->guardia );
			return ok;
		}
	/* se arrivo a questo punto la guardia è locked, controllo se ci sono threads in waiting */
	if ( rwl->r_wait || rwl->w_wait )
		{
			printf ("\nCi sono ancora thread in coda, non posso distruggere l'RW-Lock\n");
			ok = pthread_mutex_unlock ( &rwl->guardia );
			return ok;
		}
	/* se e' tutto a posto setto la validita' a NO e sblocco */
	rwl->to_use = NO;
	pthread_mutex_unlock ( &rwl->guardia );

	ok = pthread_mutex_destroy ( &rwl->guardia );
	if ( !ok )
		{
			printf ("\nErrore distruzione mutex GUARDIA\n");
			return -1;
		}	
	ok = pthread_cond_destroy ( &rwl->canread );
	if ( !ok )
		{
			printf ("\nErrore distruzione variabile condizionale (I can read?)\n");
			return -1;
		}	
	ok = pthread_cond_destroy ( &rwl->canwrite );
	if ( !ok )
		{
			printf ("\nErrore distruzione variabile condizionale (I can write?)\n");
			return -1;
		}	
	return 0;
}

int thread_rwlock_rdlock ( to_rwl rwl )
{
	int ok;
	/* check validità dell'RW-Lock */
	if ( !rwl->to_use )
		{
			printf ("\nL'RW-Lock e' corrotto!!!\n");
			return -1;		
		}
	/* provo a prendere possesso dell'RW-Lock */
	do {
		ok = pthread_mutex_trylock ( &rwl->guardia );
		/* se l'RW-Lock è EBUSY, allora incremento conta_conflitti */
		if ( ok )
			{
				conta_conflitti(1);		
			}
	} while ( ok );
	/* a questo punto ho il lock sul mutex, devo controllare la condition canread */
	thread_rwlock_tryrdlock ( rwl );
	return 0;
}

void thread_rwlock_tryrdlock ( to_rwl rwl )
{
	/* controllo e aggiorno i registri */	
	if ( rwl->w_wait == 0 && rwl->w_run == 0 )
		{	
			rwl->r_run++;
			pthread_mutex_unlock ( &rwl->guardia );
		}
	else
		{
			rwl->r_wait++;
			pthread_cond_wait ( &rwl->canread, &rwl->guardia );
			pthread_mutex_unlock ( &rwl->guardia );
		}
}

int thread_rwlock_wrlock ( to_rwl rwl )
{
	int ok;
	/* check validità dell'RW-Lock */
	if ( !rwl->to_use )
		{
			printf ("\nL'RW-Lock e' corrotto!!!\n");
			return -1;		
		}
	/* provo a prendere possesso dell'RW-Lock */
	do {
		ok = pthread_mutex_trylock ( &rwl->guardia );
		/* se l'RW-Lock è EBUSY, allora incremento conta_conflitti */
		if ( ok )
			{
				conta_conflitti(1);		
			}
	} while ( ok );
	/* a questo punto ho il lock sul mutex, devo controllare la condition canwrite */
	thread_rwlock_trywrlock ( rwl );
	return 0;
}

void thread_rwlock_trywrlock ( to_rwl rwl )
{
	/* controllo e aggiorno i registri */	
	if ( rwl->w_wait == 0 && rwl->w_run == 0 && rwl->r_run == 0 )
		{
			rwl->w_run++;
			pthread_mutex_unlock ( &rwl->guardia );
		}
	else
		{
			rwl->w_wait++;
			pthread_cond_wait ( &rwl->canwrite, &rwl->guardia );
			pthread_mutex_unlock ( &rwl->guardia );
		}
}

int thread_rwlock_rdunlock ( to_rwl rwl )
{
	int ok;
	/* check validità dell'RW-Lock */
	if ( !rwl->to_use )
		{
			printf ("\nL'RW-Lock e' corrotto!!!\n");
			return -1;		
		}
	/* provo a prendere possesso dell'RW-Lock */
	do {
		ok = pthread_mutex_trylock ( &rwl->guardia );
		/* se l'RW-Lock è EBUSY, allora incremento conta_conflitti */
		if ( ok )
			{
				conta_conflitti(1);		
			}
	} while ( ok );
	/* a questo punto ho il lock sul mutex, devo aggiornare i registri e poi uscire */
	rwl->r_run--;

	pthread_mutex_unlock ( &rwl->guardia );
	if ( !rwl->r_run && rwl->w_wait )
		pthread_cond_signal ( &rwl->canwrite );
	return 0;
}

int thread_rwlock_wrunlock ( to_rwl rwl )
{
	int ok;
	/* check validità dell'RW-Lock */
	if ( !rwl->to_use )
		{
			printf ("\nL'RW-Lock e' corrotto!!!\n");
			return -1;		
		}
	/* provo a prendere possesso dell'RW-Lock */
	do {
		ok = pthread_mutex_trylock ( &rwl->guardia );
		/* se l'RW-Lock è EBUSY, allora incremento conta_conflitti */
		if ( ok )
			{
				conta_conflitti(1);		
			}
	} while ( ok );
	/* a questo punto ho il lock sul mutex, devo aggiornare i registri e poi uscire */
	rwl->w_run--;

	pthread_mutex_unlock ( &rwl->guardia );
	if ( rwl->w_wait )
		pthread_cond_signal ( &rwl->canwrite );
	else
		pthread_cond_broadcast ( &rwl->canread );
	
	return 0;	
}
file linkedlist.h
Codice:
#ifndef _LINKEDLIST_H__
#define _LINKEDLIST_H__

typedef struct impiegato impiegato_t;

struct impiegato {
  char *nome;               /* nome impiegato JAN### */
  int  salario;             /* salario percepito     */
  struct impiegato *next;   /* puntatore alla struttura successiva */
};

impiegato_t  lista_impiegati;

int    E_THREADS     = 1;     /* numero di thread che eseguono il trasferimento */ 
int    F_THREADS     = 10;    /* numero di thread che eseguono l'aumento        */
int    N_IMPIEGATI   = 1000;  /* numero di impiegati iniziali                   */
int    N_AUMENTI     = 100;   /* numero di impiegati che ricevono l'aumento     */
int    AUMENTO_DELAY = 100;   /* ritardo per operazione aumento in ms           */
int    TRASFER_DELAY = 100;   /* ritardo per operazione di trasferimento        */

/* prototipi di funzione */
void conta_conflitti(int i);
void conta_trovati(int i);

void stampa_lista_impiegati(impiegato_t *p);
impiegato_t *trova_impiegato(char *nome);
void aggiungi_lista_impiegati(char *nome);
void crea_lista_impiegati();

void  da_aumento_impiegato(impiegato_t *p);
void *da_aumento_lista_impiegati(void *arg);
impiegato_t *crea_lista_aumenti(int seed1);

void trasferisci_impiegato(impiegato_t *p);
void *trasferisci_lista_impiegati(void *arg);
impiegato_t *crea_lista_trasfer(int s);

void delay(int sleep_ms,int cpu_us);
#endif
Siete la mia speranza, se qualcuno ce la fa vince pizza e birra dalle parti di Ferrara!!

Grazie a tutti
f.bandiera è offline   Rispondi citando il messaggio o parte di esso
Old 08-03-2008, 09:22   #11
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
L'unico consiglio che ti posso dare è andare per gradi e non scrivere tutto il codice in una volta sola.
Secondo me ha poco senso implementare il trylock, magari lo puoi fare dopo, prima implementa solo lock e unlock.
Non so a cosa ti serva conta_conflitti, me lo puoi spiegare ?
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 08-03-2008, 11:36   #12
f.bandiera
Member
 
Iscritto dal: Apr 2007
Messaggi: 51
Ciao, adesso provo a seguire il tuo consiglio e a provare prima la soluzione con lock e unlock (not trylock).

Conta_conflitti fa parte delle funzioni date dal professore, ed è in relazione proprio con i trylock, ovvero ogni volta che una thread effettua un trylock ritornando EBUSY, allora viene chiamata contaconflitti(1) che dovrebbe, alla fine (dopo la chiamata conta_conflitti (-1) nel main) printare su schermo in numero di volte che le varie thread non hanno potuto accedere direttamente alla struttura dati perchè già bloccata da un'altra...

Purtroppo il progetto che ci è stato dato è pensato per "vedere" il funzionamento delle Pthread e i prob di sincronizzazione, ma la "logica" del programma è decisamente carente (e questo, per me personalmente, è un problema, perchè perdo tempo anche solo a capire dove si vuole andare a parare..)

La "prima versione" del progetto era di effettuare la sincronizzazione usando 1 SOLO MUTEX GLOBALE, ovvero mettendo un bel lock all'ACCESSO alla lista!
che senso ha? allora vuol dire che le thread accedono alla struttura dati una sola alla volta, indipendentemente dal loro compito... quindi dove vanno a finire i vantaggi dell'esecuzione in parallelo????

La seconda parte è appunto quella di implementare un nostro rw-lock usando mutex e variable condition.... ok, ci sta!
ma poi ci chiede di applicarlo al programma precedente al posto del mutex globale, e anche qui...
Dato che le ETHREAD modificano la lista (cancellando elementi) sono i nostri "writers", per semplice esclusione le FTHREAD sono le readers (come confermato dal prof).
Problema: è vero che le fthread non cambiano le DIMENSIONI della lista concatenata, ma vanno comunque a SCRIVERE all'interno di un campo della "struct elemento"... quindi in teoria (almeno per quello che ho capito studiando) non sono proprio solo readers, e anche il loro accesso agli elementi andrebbe regolamentato, in quanto diversamente potrebbero accadere context switch nel momento sbagliato e 2 o più FTHREAD che vogliono incrementare lo stipendio allo stesso elemento potrebbero "sbagliare".....

Insomma, per me è proprio il testo dell'esercizio che è un po' confuso!
ma è il penultimo progetto prima dell'esame ho fatto bene gli altri e voglio far bene anche questo....

Va beh, polemiche a parte ho da chiedere una cosa specifica...

quando una thread mi va in wait su una variable conditions, rilascia il lock del mutex.
poi quando un'altra thread manda un signal sulla conditions...
la thread che si risveglia acquisisce o TENTA di ACQUISIRE nuovamente il mutex, e poi da dove riprende la sua esecuzione?
dall'istruzione sucessiva alla chiamata di wait?
oppure "testa" nuovamente la condition(finendo eventualmente di nuovo in wait) ?

Ciao e grazie
f.bandiera è offline   Rispondi citando il messaggio o parte di esso
Old 08-03-2008, 17:41   #13
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
L'esecuzione riparte da dopo la pthread_cond_wait con la mutex acquisita.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 08-03-2008, 19:20   #14
f.bandiera
Member
 
Iscritto dal: Apr 2007
Messaggi: 51
ciao, alla fine credo di essere riuscito a mettere tutto a posto!
Grazie per tutti i vostri consigli...


Ora vorrei chiedere un altro favore, se allego i file che ho scritto, non è che ci potreste dare una occhiata?

Io li ho fatti e mi sembrano corretti, ma per un po' di test alle volte è meglio chiedere aiuto a persone più esperte!

Sono anche contattabile in pvt all'indirizzo
[email protected]

Grazie 1000 a todos!!!!
CIAOOOOOOOOOOOOOOOOOOOOOOOOOO
Allegati
File Type: zip prog3_2punto.zip (3.7 KB, 19 visite)
f.bandiera è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Polestar 3 Performance, test drive: comodità e potenza possono convivere Polestar 3 Performance, test drive: comodit&agra...
Qualcomm Snapdragon X2 Elite: l'architettura del SoC per i notebook del 2026 Qualcomm Snapdragon X2 Elite: l'architettura del...
Recensione DJI Mini 5 Pro: il drone C0 ultra-leggero con sensore da 1 pollice Recensione DJI Mini 5 Pro: il drone C0 ultra-leg...
ASUS Expertbook PM3: il notebook robusto per le aziende ASUS Expertbook PM3: il notebook robusto per le ...
Test ride con Gowow Ori: elettrico e off-road vanno incredibilmente d'accordo Test ride con Gowow Ori: elettrico e off-road va...
Grazie a VLT è stata misurata dir...
Blue Origin annuncia un aerofreno ripieg...
Blue Origin annuncia una nuova versione ...
LG UltraFine evo 6K: il primo monitor al...
DJI cambia direzione: investe in Elegoo ...
Black Friday Narwal 2025: risparmi da ca...
Phishing evoluto contro Apple ID: caso f...
Prestazioni in discesa nei giochi? NVIDI...
Addio ai banner dei cookie? L'UE spinge ...
Le offerte Black Friday per gli smartpho...
Il controllo qualità degli iPhone...
Qualcomm Snapdragon X Elite vola con il ...
A2RL Season 2: storia, innovazione e sor...
Core Ultra Series 3: Intel conferma l'ev...
Black Friday Amazon: la GeForce RTX 5070...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 07:40.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v