PDA

View Full Version : Thread e pthread_cond_broadcast


Arpeda
16-09-2004, 15:28
ragazzi mi serve un chiarimento su questo programmino:


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

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int variabile1 = 0;
int variabile2 = 0;

void* test1( void *argv )
{
printf( "Thread %li in attesa su mutex1\n", pthread_self() );

pthread_mutex_lock( &mutex1 );
while( variabile1 == 0 )
pthread_cond_wait( &cond, &mutex1 );

pthread_mutex_unlock( &mutex1 );

printf("[%li] variabile è ora %d mutex1\n", pthread_self(), variabile1 );

return 0;
}

void* test2( void *argv )
{
printf( "Thread %li in attesa su mutex2\n", pthread_self() );

pthread_mutex_lock( &mutex2 );
while( variabile2 == 0 )
pthread_cond_wait( &cond, &mutex2 );

pthread_mutex_unlock( &mutex2 );

printf("[%li] variabile è ora %d\n mutex2", pthread_self(), variabile2 );

return 0;
}

int main( int argc, char *argv[] )
{
pthread_t t1, t2, t3;

pthread_create( &t1, NULL, test1, NULL);
pthread_create( &t2, NULL, test2, NULL);
pthread_create( &t3, NULL, test2, NULL);

sleep( 2 );

pthread_mutex_lock( &mutex1 );
variabile1 = 1;
pthread_mutex_unlock( &mutex1 );

pthread_mutex_lock( &mutex2 );
variabile2 = 1;
pthread_mutex_unlock( &mutex2 );

pthread_cond_broadcast( &cond );

pthread_join( t1, NULL );
pthread_join( t2, NULL );
pthread_join( t3, NULL );

return 0;
}


come output ottengo questo:

bash-2.05b$ ./tb
Thread 1083485104 in attesa su mutex1
Thread 1091881904 in attesa su mutex2
Thread 1100274608 in attesa su mutex2
[1083485104] variabile è ora 1 mutex1


e l'esecuzione non termina.
Ora vorrei capire bene il perchè. La pthread_cond_broadcast non dovrebbe svegliare _tutti_ i thread in attesa su cond?

la man page riporta queste righe
The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads call-
ing pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling
behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal().

In pratica dovrei riuscire a svegliare i thread anche se non sono in possesso del mutex che è stato associato a cond durante la wait.
Se così non fosse(come sembra) mi troverei in difficoltà, perchè ho threads in attesa sulla stessa variabile cond ma blocco mutex differenti.
per ovviare posso usare pthread_cond_signal e richiamarla una volta per thread ma vorrei evitare. Sapete darmi qualche dritta?

Ciao
Arpeda

ilsensine
16-09-2004, 15:43
WorksForMe (TM)

ilsensine
16-09-2004, 15:49
Rettifico: mi funziona su un biprocessone, non su un monoprocessore (!).
Utilizzando un unico mutex, funziona anche sul monoprocessore.

Arpeda
16-09-2004, 16:16
già di questo me ne ero accorto :D
però non posso usare lo stesso mutex per bloccare i thread.
questo è un esempietto per cercare di capire il funzionamento corretto della broadcast che poi devo applicare in un contesto più ampio.
non ci sono problemi a fare diverse signal ma
1) stilisticamente non mi piace :cool:
2) perchè la broadcast (e 2 mutex) non dovrebbe funzionare bene anche su un monoprocessore? :D

sembrerebbe che su un monoprocessore riveglia l'accoppiata mutex/condizione
ma se modifico

pthread_mutex_lock( &mutex1 );
variabile1 = 1;
pthread_mutex_unlock( &mutex1 );

pthread_mutex_lock( &mutex2 );
variabile2 = 1;
pthread_mutex_unlock( &mutex2 );

pthread_cond_broadcast( &cond );


in quest'altro:

pthread_mutex_lock( &mutex1 );
variabile1 = 1;
pthread_cond_broadcast( &cond );
pthread_mutex_unlock( &mutex1 );

pthread_mutex_lock( &mutex2 );
variabile2 = 1;
pthread_cond_broadcast( &cond );
pthread_mutex_unlock( &mutex2 );


i thread t2 e t3 non vengono svegliati (dalle prove che ho fatto non gli arriva proprio la segnalazione dalla broadcast) ne dalla prima ne dalla seconda :(

Any ideas?
ciao
Arpeda

ilsensine
16-09-2004, 16:32
Perché non fai le cose come devono essere fatte?

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

int variabile1 = 0;
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;

int variabile2 = 0;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;

void* test1( void *argv )
{
printf( "Thread %li in attesa su mutex1\n", pthread_self() );

pthread_mutex_lock(&mutex1);
while(!variabile1)
pthread_cond_wait(&cond1, &mutex1);
pthread_mutex_unlock(&mutex1);

printf("[%li] variabile1 è ora %d\n", pthread_self(), variabile1);

return 0;
}

void* test2( void *argv )
{
printf( "Thread %li in attesa su mutex2\n", pthread_self() );

pthread_mutex_lock( &mutex2);
pthread_cond_wait( &cond2, &mutex2);
pthread_mutex_unlock( &mutex2);

printf("[%li] variabile è ora %d\n", pthread_self(), variabile2 );

return 0;
}

int main( int argc, char *argv[] )
{
pthread_t t1, t2, t3;

pthread_create( &t1, NULL, test1, NULL);
pthread_create( &t2, NULL, test2, NULL);
pthread_create( &t3, NULL, test2, NULL);

sleep(1);

pthread_mutex_lock(&mutex1);
variabile1 = 1;
pthread_mutex_unlock(&mutex1);
pthread_mutex_lock(&mutex2);
variabile2 = 1;
pthread_mutex_unlock(&mutex2);

pthread_cond_broadcast( &cond1 );
pthread_cond_broadcast( &cond2 );

pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);

return 0;
}

Ovvero: UN mutex per UNA variabile di condizione per UN set di dati

Nel tuo programma c'è un errore concettuale: due thread accedono a cond senza serializzazione (in quanto uno blocca un mutex, il secondo ne blocca un altro => race su cond).

Arpeda
16-09-2004, 16:41
Azz nn avevo pensato ad una race condition su cond! :p

Grazie della dritta ora vedo un po se posso modificare le cose.

Ciao
Arpeda