Questions à choix multiples¶
Question 1. Utilisation de pthread_create(3)¶
f
en lui passant la chaîne de caractères s
comme argument. Lequel ?void * f( void * param) {
// incomplet
return NULL;
}
int main (int argc, char *argv[]) {
pthread_t t;
int err;
char *s;
err=pthread_create(&t,NULL,&(f),(void *) s);
}
void * f (void * param) {
// incomplet
return NULL;
}
int main (int argc, char *argv[]) {
pthread_t t;
int err;
char *s;
err=pthread_create(&t,NULL,&(f),(void *) &s);
}
void f(void * param) {
// incomplet
return NULL;
}
int main (int argc, char *argv[]) {
pthread_t *t;
int err;
char *s;
err=pthread_create(t,NULL,*f,(void *) *s);
}
void *f(void ** param) {
// incomplet
return NULL;
}
int main (int argc, char *argv[]) {
pthread_t t;
int err;
char s;
err=pthread_create(&t,NULL,&(f),(void *) s);
}
Question 2. Passage d’arguments à un thread¶
Considérons un thread qui a pour objectif de convertir une fraction en un nombre en virgule flottante. Ce n’est pas une bonne utilisation de threads puisque le calcul à effectuer est très simple, mais cela nous permettra de voir comment un thread peut recevoir des arguments directement. En dehors des threads, cette fonction de conversion pourrait s’écrire :
struct fraction {
int num;
int denum;
};
typedef struct fraction Fraction_t;
float tofloat(Fraction_t t) {
return (float) t.num/ (float) t.denum;
}
void *mythread(void * param) {
Fraction_t *f=(Fraction_t *) param;
float *r=(float *)malloc(sizeof(float));
*r=(float) f->num/ (float) f->denum;
return((void *) r);
}
int main (int argc, char *argv[]) {
pthread_t t;
Fraction_t f;
f.num=1;
f.denum=3;
float *r;
int err;
err=pthread_create(&t,NULL,&mythread,&(f));
err=pthread_join(t,(void **) &r);
}
void *mythread(void * param) {
Fraction_t f= *param;
float r;
r=(float) f.num/ (float) f.denum;
return((void *) &r);
}
int main (int argc, char *argv[]) {
pthread_t t;
Fraction_t f;
f.num=1;
f.denum=3;
float r;
int err;
err=pthread_create(&t,NULL,&mythread,&(f));
err=pthread_join(t,(void **) &r);
}
void *mythread(void * param) {
Fraction_t *t=(Fraction_t *) param;
float *r=(float *)malloc(sizeof(float));
*r=(float) t->num/ (float) t->denum;
return((void *) r);
}
int main (int argc, char *argv[]) {
pthread_t t;
Fraction_t f;
f.num=1;
f.denum=3;
float r;
int err;
err=pthread_create(&t,NULL,&mythread,&f);
r=pthread_join(t,NULL);
}
float mythread(Fraction_t param) {
float *r=(float *)malloc(sizeof(float));
*r=(float) param->num/ (float) param->denum;
return(r);
}
int main (int argc, char *argv[]) {
pthread_t t;
Fraction_t f;
f.num=1;
f.denum=3;
printf("%f \n",tofloat(f));
float *r;
int err;
err=pthread_create(&t,NULL,&mythread,&(f));
err=pthread_join(t,(void *) &r);
}
Question 3. Initialisation de mutex¶
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
err= pthread_mutexattr_init(&attr);
if(err!=0)
error(err,"pthread_mutexattr_init");
err=pthread_mutex_init( &mutex, &attr);
if(err!=0)
error(err,"pthread_mutex_init");
pthread_mutex_t mutex;
err=pthread_mutex_init( &mutex, NULL);
if(err!=0)
error(err,"pthread_mutex_init");
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
err= pthread_mutexattr_init(attr);
if(err!=0)
error(err,"pthread_mutexattr_init");
err=pthread_mutex_init(mutex, attr);
if(err!=0)
error(err,"pthread_mutex_init");
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
err= pthread_mutexattr_init(&attr);
if(err!=0)
error(err,"pthread_mutexattr_init");
err=pthread_mutex_init(&mutex, attr);
if(err!=0)
error(err,"pthread_mutex_init");
pthread_mutex_t *mutex;
pthread_mutexattr_t *attr;
err= pthread_mutexattr_init(attr);
if(err!=0)
error(err,"pthread_attr_init");
err=pthread_mutex_init(mutex, attr);
if(err!=0)
error(err,"pthread_mutex_init");
Question 4. Utilisation de pthread_mutex_lock(3posix) et pthread_mutex_unlock(3posix)¶
update
qui prend comme arguments la variable à mettre à jour et le mutex qui y est associé. Parmi les extraits ci-dessous, lequel permet de mettre à jour la variable sans risque de contention entre les threads qui y accèdent ?void update(int * val, pthread_mutex_t * mutex) {
err=pthread_mutex_lock(mutex);
if(err!=0)
error(err,"pthread_mutex_lock");
// mise à jour de la variable globale
err=pthread_mutex_unlock(mutex);
if(err!=0)
error(err,"pthread_mutex_unlock");
}
void update(int * val, pthread_mutex_t * mutex) {
err=pthread_mutex_unlock(mutex);
if(err!=0)
error(err,"pthread_mutex_unlock");
// mise à jour de la variable globale
err=pthread_mutex_lock(mutex);
if(err!=0)
error(err,"pthread_mutex_lock");
}
void update(int val, pthread_mutex_t mutex) {
err=pthread_mutex_lock(mutex);
if(err!=0)
error(err,"pthread_mutex_lock");
// mise à jour de la variable globale
err=pthread_mutex_unlock(mutex);
if(err!=0)
error(err,"pthread_mutex_unlock");
}
void update(int * val, pthread_mutex_t mutex) {
err=pthread_mutex_lock(&mutex);
if(err!=0)
error(err,"pthread_mutex_lock");
// mise à jour de la variable globale
err=pthread_mutex_unlock(&mutex);
if(err!=0)
error(err,"pthread_mutex_unlock");
}
Question 5. Utilisation de plusieurs mutex¶
Dans certains programmes, il est nécessaire de définir plusieurs mutex qui sont utilisés par différents threads pour gérer l’accès à des variables partagées. Considérons un programme qui utilise trois variables globales et est découpé en plusieurs threads.
long a=5; // variable globale partagée
long b=7; // variable globale partagée
long c=9; // variable globale partagée
pthread_mutex_t x; // variable globale associée à a
pthread_mutex_t y; // variable globale associée à b
pthread_mutex_t z; // variable globale associée à c
void update(int * val1, int * val2, pthread_mutex_t * mutex1, pthread_mutex_t * mutex2) {
err=pthread_mutex_lock(mutex1);
if(err!=0)
error(err,"pthread_mutex_lock");
err=pthread_mutex_lock(mutex2);
if(err!=0)
error(err,"pthread_mutex_lock");
// mise à jour val1
// mise à jour val2
err=pthread_mutex_unlock(mutex1);
if(err!=0)
error(err,"pthread_mutex_unlock");
err=pthread_mutex_unlock(mutex2);
if(err!=0)
error(err,"pthread_mutex_unlock");
}
a
, b
et c
. Parmi les fragments de code ci-dessous qui utilisent plusieurs threads, un seul est correct. Lequel ?// thread A
update(&a,&b,&x,&y);
update(&a,&c,&x,&z);
// thread B
update(&b,&c,&y,&z);
update(&a,&c,&x,&z);
// thread A
update(&a,&b,&x,&y);
update(&b,&c,&y,&z);
// thread B
update(&b,&c,&y,&z);
update(&a,&c,&x,&z);
// thread A
update(&a,&b,&x,&y);
update(&c,&a,&z,&x);
// thread B
update(&b,&c,&y,&z);
update(&a,&c,&x,&z);
// thread A
update(&a,&b,&x,&y);
update(&a,&c,&x,&z);
// thread B
update(&b,&c,&y,&z);
update(&c,&a,&z,&x);
// thread A
update(&a,&b,&x,&y);
update(&a,&b,&x,&y);
// thread B
update(&b,&a,&y,&x);
update(&a,&c,&x,&z);
Question 6. Utilisation des sémaphores¶
sem_t semaphore;
sem_init(&semaphore, 0,1);
// ...
sem_destroy(&semaphore);
sem_t semaphore;
sem_init(semaphore, 1,0);
// ...
sem_destroy(semaphore);
sem_t semaphore;
sem_init(&semaphore, 1,0);
// ...
sem_destroy(&semaphore);
sem_t *semaphore;
semaphore=(sem_t *)malloc(sizeof(struct sem_t));
if (semaphore==NULL)
error("malloc");
sem_init(semaphore, 1, 0);
// ...
sem_destroy(semaphore);
sem_t *semaphore;
semaphore=(sem_t *)malloc(sizeof(struct sem_t));
if (semaphore==NULL)
error("malloc");
sem_init(semaphore, 1, 0);
// ...
sem_destroy(&semaphore);
.. comment::
`sem_init(3)`_ prend comme troisième argument la valeur initiale du sémaphore. `sem_destroy(3)`_ prennent comme premier argument un pointeur vers une structure ``sem_t``.
Question 7. Exclusion mutuelle¶
static sem_t semaphore;
long global=0;
int increment(int i) {
// ...
}
void *inc(void * param) {
for(int j=0;j<1000000;j++) {
sem_wait(&semaphore);
global=increment(global);
sem_post(&semaphore);
}
}
int main (int argc, char *argv[]) {
pthread_t thread[NTHREADS];
int err;
sem_init(&semaphore, 0,1);
for(int i=0;i<NTHREADS;i++) {
err=pthread_create(&(thread[i]),NULL,&inc,NULL);
if(err!=0)
error(err,"pthread_create");
}
// reste non fourni
}
sem_t * semaphore;
long global=0;
int increment(int i) {
// ...
}
void *inc(void * param) {
for(int j=0;j<1000000;j++) {
sem_wait(semaphore);
global=increment(global);
sem_post(semaphore);
}
}
int main (int argc, char *argv[]) {
pthread_t thread[NTHREADS];
int err;
semaphore=(sem_t *)malloc(sizeof(sem_t))
if(semaphore==NULL)
error("malloc");
sem_init(semaphore, 0,1);
for(int i=0;i<NTHREADS;i++) {
err=pthread_create(&(thread[i]),NULL,&inc,NULL);
if(err!=0)
error(err,"pthread_create");
}
// reste non fourni
}
static sem_t semaphore;
long global=0;
int increment(int i) {
// ...
}
void *inc(void * param) {
for(int j=0;j<1000000;j++) {
sem_wait(&semaphore);
global=increment(global);
sem_post(&semaphore);
}
}
int main (int argc, char *argv[]) {
pthread_t thread[NTHREADS];
int err;
sem_init(&semaphore, 0,0);
for(int i=0;i<NTHREADS;i++) {
err=pthread_create(&(thread[i]),NULL,&inc,NULL);
if(err!=0)
error(err,"pthread_create");
}
// reste non fourni
}
static sem_t semaphore;
long global=0;
int increment(int i) {
// ...
}
void *inc(void * param) {
for(int j=0;j<1000000;j++) {
sem_post(&semaphore);
global=increment(global);
sem_wait(&semaphore);
}
}
int main (int argc, char *argv[]) {
pthread_t thread[NTHREADS];
int err;
sem_init(&semaphore, 0,0);
for(int i=0;i<NTHREADS;i++) {
err=pthread_create(&(thread[i]),NULL,&inc,NULL);
if(err!=0)
error(err,"pthread_create");
}
// reste non fourni
}
sem_t * semaphore;
long global=0;
int increment(int i) {
// ...
}
void *inc(void * param) {
for(int j=0;j<1000000;j++) {
sem_wait(semaphore);
global=increment(global);
sem_post(semaphore);
}
}
int main (int argc, char *argv[]) {
pthread_t thread[NTHREADS];
int err;
semaphore=(sem_t *)malloc(sizeof(sem_t))
if(semaphore==NULL)
error("malloc");
sem_init(semaphore, 0,0);
for(int i=0;i<NTHREADS;i++) {
err=pthread_create(&(thread[i]),NULL,&inc,NULL);
if(err!=0)
error(err,"pthread_create");
}
// reste non fourni
}
sem_t * semaphore;
long global=0;
int increment(int i) {
// ...
}
void *inc(void * param) {
for(int j=0;j<1000000;j++) {
sem_post(semaphore);
global=increment(global);
sem_wait(semaphore);
}
}
int main (int argc, char *argv[]) {
pthread_t thread[NTHREADS];
int err;
semaphore=(sem_t *)malloc(sizeof(sem_t))
if(semaphore==NULL)
error("malloc");
sem_init(semaphore, 0,0);
for(int i=0;i<NTHREADS;i++) {
err=pthread_create(&(thread[i]),NULL,&inc,NULL);
if(err!=0)
error(err,"pthread_create");
}
// reste non fourni
}
f
a la bonne signature, mais le dernier argument à pthread_create(3) doit être de typevoid *
, ors
est unchar *
et donc ce dernier argument doit être(void *) s
.