【操作系统】实验:生产者消费者问题

目录

一、实验目的

二、实验要求

三、实验步骤

四、核心代码

五、记录与处理

六、思考

七、完整报告和成果文件提取链接


一、实验目的

实现对经典的生产者—消费者问题的模拟,以便更好的理解经典进程同步问题。

二、实验要求

本实验在一个进程中执行两个线程,一个是生产者线程,一个是消费者线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。

本实验需要三个信号量:

1.互斥信号量mutex:实现进程对缓冲池的互斥使用。

2.信号量Empty:表示缓冲池中空缓冲区的数量。

3.信号量Full:表示缓冲池中满缓冲区的数量。

三、实验步骤

在同一个进程地址空间内执行两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻挡,直到新的物品被生产出来。

程序流程图:

生产者                                        

    

  消费者

     

四、核心代码

主要代码及结果分析。运行结果截图。例如:

假设缓冲区大小为10,生产者、消费者线程若干。生产者和消费者相互等效,只要缓冲池未满,生产者便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。

items代表缓冲区已经使用的资源数,spaces代表缓冲区可用资源数

mutex代表互斥锁

buf[10] 代表缓冲区,其内容类型为item

in、out代表第一个资源和最后一个资源

void *producer( void *arg ) {
    while( flag ) {
        pthread_mutex_lock( &mutex );  // 加锁,保证条件变量不会因为多线程混乱
        while( !spaces ) {  // 如果缓冲区已满,等待缓冲区不满的条件变量
            pthread_cond_wait( &notfull, &mutex );
        }
        buf[in] = current++;  // 将产品放入缓冲区
        in = ( in + 1 ) % 10;  // 更新输入指针
        items++;  // 增加产品数量
        spaces--;  // 减少空闲空间数量

        printf( "producer %zu , current = %d\n", pthread_self(), current );
        for( int i = 0; i < 10; i++ ) {
            printf( "%-4d", buf[i] );
        }
        printf( "\n\n" );

        pthread_cond_signal( &notempty );  // 通知缓冲区不空的条件变量
        pthread_mutex_unlock( &mutex );  // 解锁
    }
    pthread_exit( NULL );
}

void *consumer( void *arg ) {
    while( flag ) {
        pthread_mutex_lock( &mutex );  // 加锁,保证条件变量不会因为多线程混乱
        while( !items ) {  // 如果缓冲区为空,等待缓冲区不空的条件变量
            pthread_cond_wait( &notempty, &mutex );
        }
        buf[out] = -1;  // 从缓冲区取出产品
        out = ( out + 1 ) % 10;  // 更新输出指针
        current--;  // 减少当前产品编号
        items--;  // 减少产品数量
        spaces++;  // 增加空闲空间数量

        printf( "consumer %zu , current = %d\n", pthread_self(), current );
        for( int i = 0; i < 10; i++ ) {
            printf( "%-4d", buf[i] );
        }
        printf( "\n\n" );

        pthread_cond_signal( &notfull );  // 通知缓冲区不满的条件变量
        pthread_mutex_unlock( &mutex );  // 解锁
    }
    pthread_exit( NULL );
}

int main() {
    memset( buf, -1, sizeof(buf) );  // 初始化缓冲区为-1表示空位
    flag = true;  // 设置标志为true,表示线程可以运行
    pthread_t pro[10], con[10];  // 定义生产者和消费者线程ID数组
    int i = 0;

    for( int i = 0; i < 10; i++ ) {
        pthread_create( &pro[i], NULL, producer, NULL );  // 创建生产者线程
        pthread_create( &con[i], NULL, consumer, NULL );  // 创建消费者线程
    }

    sleep(1);  // 让线程运行一段时间
    flag = false;  // 设置标志为false,表示线程需要停止运行

    for( int i = 0; i < 10; i++ ) {
        pthread_join( pro[i], NULL );  // 等待生产者线程结束
        pthread_join( con[i], NULL );  // 等待消费者线程结束
    }

    return 0;
}

五、记录与处理

运行结果如下,由于运行结果过长,此处截取部分截图。

六、思考

信号量机制相比其他方法实现进程同步的优缺点?

信号量机制是一种实现进程同步的重要方法,与其他方法相比,它有其独特的优缺点。

优点:

1.精确控制:信号量机制通过计数方式实现对共享资源的精确控制。它允许程序员设定一个资源的最大访问数量,并在达到这个数量时阻止其他进程访问,从而避免了资源的过度竞争和冲突。

2.灵活性强:信号量机制支持多种同步模式,如互斥、同步等。通过调整信号量的初始值和操作方式,可以实现不同的同步需求,适用于各种复杂的并发场景。

3.实现简单:信号量机制的实现相对简单,容易理解和使用。它只需要定义一些基本的操作(如P操作和V操作),并在程序中调用这些操作即可实现进程同步。

缺点:

1.需要公共内存:信号量机制必须有公共内存来存储信号量的值。这意味着它不能直接在分布式操作系统中使用,因为分布式系统没有全局共享的内存空间。这是信号量机制的一个主要限制。

2.编程复杂性:虽然信号量机制的实现相对简单,但在使用它来实现进程同步时,程序员需要仔细考虑如何设置信号量的初始值、如何调用P操作和V操作等。这需要一定的编程经验和技能,否则容易出现死锁、饥饿等问题。

3.难以调试和维护:由于信号量机制的实现涉及多个进程之间的交互和协作,因此它的调试和维护相对困难。一旦出现错误或问题,需要仔细分析多个进程的执行轨迹和状态信息,才能找到问题的根源并进行修复。

与其他方法相比,信号量机制在精确控制和灵活性方面具有一定的优势。然而,它也存在一些限制和缺点,如需要公共内存、编程复杂性和难以调试等。因此,在选择使用信号量机制实现进程同步时,需要根据具体的应用场景和需求进行权衡和选择。

七、完整报告和成果文件提取链接


链接:https://pan.baidu.com/s/1UbP6729pCluscVW0_9oI8w?pwd=1xki 
提取码:1xki 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值