【问题标题】:Semaphores and Deadlocks in CC中的信号量和死锁
【发布时间】:2013-10-28 21:28:56
【问题描述】:

我正在尝试使用信号量对生产者/消费者问题进行编码。我有 3 个,1 个用作互斥体,另外 2 个用作生产者和消费者可以添加/删除的缓冲区。从缓冲区添加/删除时,我使用二进制信号量来锁定/解锁它,这样全局变量就不会受到任何竞争条件的影响。生产信号量表示缓冲区中有多少可用点(可以将多少东西放入缓冲区),而消费者信号量表示可以从缓冲区中删除多少东西。我认为我的逻辑是错误的,因为我总是陷入僵局。此外,当我删除生产和消耗信号量只是为了测试程序是否执行它应该做的事情时,即使二进制信号量应该阻止它,我仍然会遇到竞争条件。我做错了什么?

enter code here
#include <stdio.h>  
#include <sys/types.h>  
#include <unistd.h> 
#include <stdlib.h>     
#include <sys/wait.h>   
#include <pthread.h>
#include </usr/include/semaphore.h>

#define MAXITEMS 100    
#define PRODUCER_NO 5   
#define NUM_PRODUCED 5 

void *producer_function (void);
void *consumer_function (void);
void add_buffer (long i);
long get_buffer ();


long sum_value = 0; 
long finished_producers;
long buffer[MAXITEMS];  
int size = 0;       
int front, rear = 0;    

pthread_t producerThread[5];
pthread_t consumerThread;
sem_t mutex, produce, consume;

int main(void)
{
    int i = 0;
    srand (time(NULL));
    sem_init (&mutex, 0, 1);
    sem_init (&produce, 0, 100);
    sem_init (&consume, 0, 0);
    for (i = 0; i < 5; i++)
    {
        pthread_create (&producerThread[i], NULL, (void *) producer_function, NULL);
    }
    pthread_create (&consumerThread, NULL, (void *) consumer_function, NULL);
    for (i = 0; i < 5; i++)
    {
        pthread_join (producerThread[i], NULL);
    }
    pthread_join (consumerThread, NULL);
    return(0);
}

void *producer_function(void)
{   
    long counter = 0;
    long producer_sum = 0L;
    while (counter < NUM_PRODUCED) 
    {
        sem_wait (&mutex);
        sem_wait (&produce);
        long rndNum = rand() % 10; 
        producer_sum += rndNum;
        add_buffer (rndNum);
        sem_post (&consume);
        counter++;
        if (counter == NUM_PRODUCED)
        {
            finished_producers++;
        }
        sem_post (&mutex);
        usleep(1000);
    }

    printf("--+---+----+----------+---------+---+--+---+------+----\n");
    printf("The sum of produced items for this producer at the end is: %ld \n", producer_sum);
    printf("--+---+----+----------+---------+---+--+---+------+----\n");
    return(0);
}

void *consumer_function (void)
{   
    while (1) 
    {
        sem_wait (&mutex);
        sem_wait (&consume);
        long readnum = get_buffer();
        sem_post (&produce);
        sum_value += readnum;
        sem_post (&mutex);
        //printf ("%ld\n", sum_value);
        if ((finished_producers == PRODUCER_NO) && (size == 0))
        {
            printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
            printf("The sum of the all produced items at the end is: %ld \n", sum_value);
            printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
            break;
        }
    }
}

void add_buffer(long i){
    buffer[rear] = i;
    rear = (rear+1) % MAXITEMS;
    size++;
}

long get_buffer(){
    long v;
    v = buffer[front];
    front = (front+1) % MAXITEMS;
    size--;
    return v;
}

【问题讨论】:

  • 您可能误解了semaphores 的用途:保护对数据的访问,而不是实现数据或将消费者或生产者与数据联系起来。在您的情况下,只需要一个信号量来控制对缓冲区(即共享资源)的访问。然后,所有消费者和生产者将使用该信号量并排队以独占访问您的缓冲区,而只有一个线程可以以任何必要的方式操作缓冲区。 (另外,在您的 semaphore.h 包含中,删除绝对路径,这是 不好的 做法。)
  • 我知道信号量的用途,我知道只需要 1 个,但无论如何我都看不出我的代码有什么问题。
  • 当你在修复事物的过程中,修复你的线程程序。他们必须是void* func(void*)。在这两种情况下,参数列表都是错误的,消费者线程甚至根本没有返回任何东西。而且演员阵容都是不正确的,如果做得好,也是不必要的。
  • 是的,我从来都不擅长使用指针。而且我很确定消费者线程没有返回任何内容,因为程序遇到死锁并且大小永远不会达到零。
  • 部分是finished_producers 处理。您实际上是在尝试使用相同的互斥锁来保护缓冲区和该计数器,而这种组织方式是无法做到的。您是否必须为此仅使用信号量? (这不是交易破坏者,只是痛苦,这就是我问的原因)。

标签: c


【解决方案1】:

用户2929779,

我认为在等待消费者中的消费通知时,不锁定互斥锁至关重要,反之亦然,生产者中的生产通知。想象一下,您因为等待消费通知而被阻止,并且没有生产者能够发布这样的通知,然后您的消费者保持互斥锁锁定,并且没有生产者有机会生产新项目......

所以这里的顺序很重要: 1.) 首先等待来自远程端的通知 2.) 锁定互斥锁 3.) 修改全局数据 4.) 释放互斥锁 5.) 通知远端

试试这个:

void *producer_function(void)
{   
    long counter = 0;
    long producer_sum = 0L;
    while (counter < NUM_PRODUCED) 
    {

        sem_wait (&produce);
        sem_wait (&mutex);
        long rndNum = rand() % 10;
        producer_sum += rndNum;
        add_buffer (rndNum);
        counter++;
        if (counter == NUM_PRODUCED)
        {
            finished_producers++;
        }
        sem_post (&mutex);      
        sem_post (&consume);
        usleep(1000);
    }

    printf("--+---+----+----------+---------+---+--+---+------+----\n");
    printf("The sum of produced items for this producer at the end is: %ld \n", producer_sum);
    printf("--+---+----+----------+---------+---+--+---+------+----\n");
    return(0);
}

void *consumer_function (void)
{   
    while (1) 
    {

        sem_wait (&consume);
        sem_wait (&mutex);
        long readnum = get_buffer();
        sum_value += readnum;
        if ((finished_producers == PRODUCER_NO) && (size == 0))
        {
            printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
            printf("The sum of the all produced items at the end is: %ld \n", sum_value);
            printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
            break;
        }
        sem_post (&mutex);
        sem_post (&produce);

    //printf ("%ld\n", sum_value);
    }
    return(0);
}

附:现在忽略系统调用的返回值只是为了展示示例实现......

附言另请参阅 wiki http://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem#Using_semaphores 上的伪代码 ...

【讨论】:

    猜你喜欢
    • 2021-03-20
    • 2019-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2021-05-09
    • 1970-01-01
    相关资源
    最近更新 更多