gila75 ha scritto:
E..però se si usano i mutex, dovrai aspettare qualcosa, quindi ricado nella sequenzialità...
porca miseria, devo trovare del buon materiale su cui studiare, o un bell'esempio di mutex.
Mi aggrego e restando sull'idea del produttore/consumatore/i, con e senza mutua esclusione, ti allego un esempio per poterci smanettare un po'.
Prova a cambiare questa parte, o altro se preferisci, e verificarne l'andamento
Codice: Seleziona tutto
#define MUTEX 0 /* 0 => NO_MUTEX , 1 => MUTEX */
#define NTHREAD_CONSUMER 24 /* CONSUMER THREADS to be created */
#define MAX_ITER 100 /* ITERATION FOR PRODUCER */
#define MAX_ARR 10 /* BUFFER SIZE */
#define PAUSE_PRODUCER usleep(0)
#define PAUSE_CONSUMER usleep(400)
Codice: Seleziona tutto
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h> /* usleep */
#define MUTEX 0 /* 0 => NO_MUTEX , 1 => MUTEX */
#define NTHREAD_CONSUMER 24 /* CONSUMER THREADS to be created */
#define MAX_ITER 100 /* ITERATION FOR PRODUCER */
#define MAX_ARR 10 /* BUFFER SIZE */
#define PAUSE_PRODUCER usleep(0)
#define PAUSE_CONSUMER usleep(400)
struct coda
{
char buf[MAX_ARR][8];
int nmemb,back,front;
char finish;
pthread_mutex_t mutex;
};
#if !MUTEX
#define pthread_mutex_lock(x) ;
#define pthread_mutex_unlock(x) ;
#endif
void *producer (void *args)
{
struct coda *coda = args;
int n = 1;
while (n<=MAX_ITER)
{
pthread_mutex_lock(&coda->mutex);
if (coda->nmemb < MAX_ARR)
{
snprintf(&coda->buf[coda->back][0],8,"0x%02X",n);
printf ("add %s (ndx=%d) \n",
coda->buf[coda->back],coda->back);
coda->back=(coda->back+1)%MAX_ARR;
coda->nmemb++;
n++;
}
pthread_mutex_unlock(&coda->mutex);
PAUSE_PRODUCER;
}
pthread_mutex_lock(&coda->mutex);
coda->finish=1;
pthread_mutex_unlock(&coda->mutex);
pthread_exit (NULL);
}
void *consumer (void *args)
{
struct coda *coda=args;
while(1)
{
pthread_mutex_lock(&coda->mutex);
if (coda->finish && coda->nmemb<=0)
{
pthread_mutex_unlock(&coda->mutex);
break;
}
if (coda->nmemb>0)
{
printf ("del %s (ndx=%d id=%lu nmemb=%d)\n",
coda->buf[coda->front],coda->front,
pthread_self(),coda->nmemb);
coda->front=(coda->front+1)%MAX_ARR;
coda->nmemb--;
}
pthread_mutex_unlock(&coda->mutex);
PAUSE_CONSUMER;
}
pthread_exit (NULL);
}
int main ()
{
static struct coda coda;
pthread_t tp,tc[NTHREAD_CONSUMER];
int i;
if (pthread_mutex_init(&coda.mutex, NULL) != 0)
{ perror("mutex_ init");return -1; }
printf ("MUTEX is %s\n",MUTEX?"ENABLE":"DISABLE");
printf ("Adding %d members to %d elements queue\n",MAX_ITER,MAX_ARR);
coda.finish=0;
/* create single producer */
if ((pthread_create (&tp, NULL, producer,&coda)))
{perror ("thread_create");return -1;}
/* create N consumer */
for (i=0;i<NTHREAD_CONSUMER;i++)
if ((pthread_create (&tc[i], NULL, consumer,&coda)))
{perror ("thread_create");return -1;}
for (i=0;i<NTHREAD_CONSUMER;i++)
pthread_join(tc[i], NULL );
pthread_join(tp, NULL );
return 0;
}
Esistono anche altre funzioni utili in questi contesti, tipo le condizioni:
Codice: Seleziona tutto
pthread_cond_wait(&condp, &the_mutex); /* wait producer */
...
pthread_cond_signal(&condc); /* wake up consumer */
Trovi qualche buon esempio e qualche dettaglio in
https://docs.oracle.com/cd/E19455-01/80 ... index.html
edit:
corretto codice sopra: n = 1 nella funzione producer
Altra versione per N producer
Codice: Seleziona tutto
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h> /* usleep */
#define MUTEX 1 /* 0 => NO_MUTEX , 1 => MUTEX */
#define NTHREAD_PRODUCER 24 /* PRODUCER THREADS to be created */
#define NTHREAD_CONSUMER 24 /* CONSUMER THREADS to be created */
#define MAX_ITER 100 /* ITERATION FOR PRODUCER */
#define MAX_ARR 10 /* BUFFER SIZE */
#define PAUSE_PRODUCER usleep(0)
#define PAUSE_CONSUMER usleep(0)
struct data
{
char buf[MAX_ARR][8]; /* queue */
int nmemb,back,front;
char finish; /* bool true/false */
int n; /* producer counter */
pthread_mutex_t mutex;
};
#if !MUTEX
#define pthread_mutex_lock(x) ;
#define pthread_mutex_unlock(x) ;
#define pthread_mutex_destroy(x) ;
#endif
#define PRINT(x,ndx) \
printf ("%s %s (tid=%lu ndx=%d nmemb=%d)\n",x,data->buf[ndx],pthread_self(),ndx,data->nmemb);
void *producer (void *args)
{
struct data *data = args;
while (1)
{
pthread_mutex_lock(&data->mutex);
if (data->n > MAX_ITER)
{
pthread_mutex_unlock(&data->mutex);
break;
}
if (data->nmemb < MAX_ARR)
{
snprintf(&data->buf[data->back][0],8,"0x%02X",data->n);
PRINT("add",data->back);
data->back=(data->back+1)%MAX_ARR;
data->nmemb++;
data->n++;
}
pthread_mutex_unlock(&data->mutex);
PAUSE_PRODUCER;
}
pthread_mutex_lock(&data->mutex);
data->finish=1;
pthread_mutex_unlock(&data->mutex);
pthread_exit (NULL);
}
void *consumer (void *args)
{
struct data *data=args;
while(1)
{
pthread_mutex_lock(&data->mutex);
if (data->finish && data->nmemb<=0)
{
pthread_mutex_unlock(&data->mutex);
break;
}
if (data->nmemb>0)
{
PRINT("\tdel",data->front);
data->front=(data->front+1)%MAX_ARR;
data->nmemb--;
}
pthread_mutex_unlock(&data->mutex);
PAUSE_CONSUMER;
}
pthread_exit (NULL);
}
int main ()
{
static struct data data;
pthread_t tp[NTHREAD_PRODUCER],tc[NTHREAD_CONSUMER];
int i;
if (pthread_mutex_init(&data.mutex, NULL) != 0)
{ perror("mutex_ init");return -1; }
printf ("MUTEX is %s\n",MUTEX?"ENABLE":"DISABLE");
printf ("Adding %d members to %d elements queue\n",MAX_ITER,MAX_ARR);
data.n=1;
/* create single producer */
for (i=0;i<NTHREAD_PRODUCER;i++)
if ((pthread_create (&tp[i], NULL, producer,&data)))
{perror ("thread_create");return -1;}
/* create N consumer */
for (i=0;i<NTHREAD_CONSUMER;i++)
if ((pthread_create (&tc[i], NULL, consumer,&data)))
{perror ("thread_create");return -1;}
for (i=0;i<NTHREAD_CONSUMER;i++)
pthread_join(tc[i], NULL );
for (i=0;i<NTHREAD_PRODUCER;i++)
pthread_join(tp[i], NULL );
pthread_mutex_destroy(&data.mutex);
return 0;
}