首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >只使用互斥锁和信号量的生产者-消费者同步(无pthread_cond)

只使用互斥锁和信号量的生产者-消费者同步(无pthread_cond)
EN

Stack Overflow用户
提问于 2019-06-26 00:37:35
回答 1查看 137关注 0票数 2

我目前正在学习如何使用pthread在linux中使用互斥量和信号量进行多线程处理,并且我一直在研究一个实现多生产者/单消费者问题的方法,它只使用了两个二进制信号量和一个互斥量来同步对有界缓冲区的访问,但是程序并没有按计划工作

代码语言:javascript
复制
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <semaphore.h>

#define QUEUESIZE 20
#define LOOP 15
#define MAX_THREADS 10

void *producer (void *args);
void *consumer (void *args);

int lambda;
int queuesi;
typedef struct {
        int buf[QUEUESIZE];
        long head, tail;
        int full, empty;
        pthread_mutex_t *mut; 
    sem_t *sem_notFull, *sem_notEmpty;
} queue;

queue *queueInit (void);
void queueDelete (queue *q);
void queueAdd (queue *q, int in);
void queueDel (queue *q, int *out);
int factorial( int i);           
int poissonfunction(int i);
int rando();

int main (int argc, char *argv[])
{
        int max_pro,max_con,j,i;
        queue *fifo;
        pthread_t prod[MAX_THREADS],cons[MAX_THREADS];

        max_con=1;
        max_pro=4;
        lambda=6;
        queuesi=4;  

        fifo = queueInit ();

        if (fifo ==  NULL) {
                fprintf (stderr, "main: Queue Init failed.\n");
                exit (1);
        }


        for(i=0; i<max_pro;i++)  
        pthread_create (&prod[i], NULL, producer,fifo);

        for(j=0;j<max_con;j++)
        pthread_create (&cons[j], NULL, consumer, fifo);

        for(i=0; i<max_pro;i++)
        pthread_join (prod[i], NULL);

        for(j=0;j<max_con;j++)
        pthread_join (cons[j], NULL);     

        queueDelete (fifo);

        return 0;
}

 void *producer (void *q)
{
        queue *fifo;
        int i,insert,sleep_time;     
        fifo = (queue *)q;

        for (i = 0; i < LOOP; i++) {
            //pthread_mutex_lock (fifo->mut);
            while (fifo->full)
               {
                    printf ("producer: queue FULL.\n");
                    sem_wait (fifo->sem_notFull);
                }

             pthread_mutex_lock (fifo->mut);
             insert=rando();     
             queueAdd (fifo, insert);  
             printf("producer item  number%d item produced  %d\n",i,insert);
             pthread_mutex_unlock (fifo->mut);

             sem_post (fifo->sem_notEmpty);
             sleep_time=poissonfunction(i);
             usleep (sleep_time);
        }

        return (NULL);
}                           

 void *consumer (void *q)
{
        queue *fifo;
        int i, d;

        fifo = (queue *)q;

        for (i = 0; i < LOOP; i++) 
        {
            //pthread_mutex_lock (fifo->mut);
            while (fifo->empty) 
            {      
               printf ("consumer: queue empty\n");
               sem_wait (fifo->sem_notEmpty);
            }
            pthread_mutex_lock (fifo->mut);
            queueDel (fifo, &d);
            pthread_mutex_unlock (fifo->mut);

            sem_post (fifo->sem_notFull);
            printf ("consumer: recieved %d.\n", d);
            usleep(2000);
        }                 

  return (NULL);
}

queue *queueInit (void)
{
        queue *q;

        q = (queue *)malloc (sizeof (queue));
        if (q == NULL) return (NULL);       
        q->empty = 1;
        q->full = 0;
        q->head = 0;
        q->tail = 0;
        q->mut = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
        pthread_mutex_init (q->mut, NULL);
    q->sem_notFull = (sem_t *) malloc (sizeof (sem_t));
        sem_init (q->sem_notFull, 0, 1);
        q->sem_notEmpty = (sem_t *) malloc (sizeof (sem_t));
        sem_init (q->sem_notEmpty,  0, 1); 

        return (q);
}

void queueDelete (queue *q)
{
        pthread_mutex_destroy (q->mut);
        free (q->mut);
        sem_destroy (q->sem_notFull);
        free (q->sem_notFull);   

        sem_destroy (q->sem_notEmpty);
        free (q->sem_notEmpty);

        free (q);
}

void queueAdd (queue *q, int in)
{
        q->buf[q->tail] = in;
        q->tail++;
        if (q->tail == queuesi)                     
        q->tail = 0;

        if (q->tail == q->head)
                q->full = 1;
        q->empty = 0;

        return;
}

void queueDel (queue *q, int *out)
{                                       
*out = q->buf[q->head];

        q->head++;
        if (q->head == queuesi)
                q->head = 0;
        if (q->head == q->tail)
                q->empty = 1;
        q->full = 0;

        return;                    
}

int factorial(int i){
 if(i==0)
  return i=1;
 else
  i=i*factorial(i-1);
return (i);
}               

int poissonfunction (int i){
    int time,c,t;
    double p;
    t = 1000;
    c = lambda*t;
    p = (pow(c,i)*exp(-c))/factorial(i);
    time =(int) p*t;
    return (time);
}

int rando(){
    int value;
    value=(int) random()/1000;
    return (value);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-26 01:33:03

我建议修改你的函数,比如:

代码语言:javascript
复制
void *producer (void *q)
{   
    queue *fifo;
    int i,insert,sleep_time;
    fifo = (queue *)q;

    for (i = 0; i < LOOP; i++) {
        pthread_mutex_lock (fifo->mut); /* take lock */
        while (fifo->full) {  /* check for fullness */
            pthread_mutex_unlock (fifo->mut); /* if full wait for things to be removed */
            sem_wait (fifo->sem_notFull); /* never sleep with lock */
            pthread_mutex_lock (fifo->mut); /* take lock an recheck the condition to handle spurious wakeups */
        }
        /* here lock is held */
        insert = rando(); /* safely manipulate the queue */
        queueAdd (fifo, insert);

        pthread_mutex_unlock (fifo->mut); /* safely release the queue */
        sem_post (fifo->sem_notEmpty);  /* wake up potential waiters */
        sleep_time=poissonfunction(i);
        usleep (sleep_time);
    }

    return (NULL);
}

void *consumer (void *q)
{
    queue *fifo;
    int i, d;

    fifo = (queue *)q;

    for (i = 0; i < LOOP; i++) { /* careful you don't produce 'enough' */
        pthread_mutex_lock (fifo->mut); /* take lock before using fifo */
        while (fifo->empty) { /* check is something to read */
            pthread_mutex_unlock (fifo->mut); /* release lock before sleep */
            sem_wait (fifo->sem_notEmpty); /* wait a sometihing to be pused in queue */
            pthread_mutex_lock (fifo->mut); /* take back lock before checking for spurious wakeup */
        }
        /* from here lock is held, queue can be safely maniplated */
        queueDel (fifo, &d); 
        pthread_mutex_unlock (fifo->mut); /* finished -> release lock */
        sem_post (fifo->sem_notFull); /* wake up eventual waiters*/

        usleep(2000);
    }

    return (NULL);
}

您需要检查虚假唤醒,因为即使队列不为空/已满,信号量也总是会被通知,因此被唤醒并不意味着队列处于正确的状态,因此需要进行测试。

您可以使用conditional_variable来处理full和empty事件,这将删除此处的信号量。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56758525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档