进程同步与互斥实验报告

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 .实验名称 进程同步与互斥 |
| 1. 实验目的 2. 通过编写程序实现进程的同步和互斥,使学生学会分析进程(线程)竞争资源现象,学习通过信号量解决进程互斥的方法。 |
| 1. 实验内容 (1)设置存放产品的缓冲区的个数为6个。 (2)信号量机制实现生产者和消费者对缓冲区的互斥访问。 (3)生产者生产产品时,要输出当前缓冲区产品的个数和存放产品的位置。 (4)消费者消费产品时,要输出当前缓冲区产品的个数和消费产品的位置。 (5)用多线程的并发实现生产者进程和消费者进程的同步。 |
| 1. 实验原理或流程图 利用信号量机制解决进程(线程)的基本方法。 在现代计算机系统中,多个进程(或线程)可能会并发执行,并争夺共享资源。这种竞争可能导致许多问题,例如数据不一致性或死锁,尤其是在生产者-消费者问题的场景中。为了有效解决这些问题,我们需要使用进程同步和互斥机制。 1. 进程同步与互斥 进程同步:在多进程或多线程的情况下,当多个进程需要按照特定的顺序执行时,进程同步是至关重要的。在生产者-消费者模型中,消费者不能在缓冲区为空时尝试消费产品,而生产者又不能在缓冲区满时创产品。因此,进程同步确保了生产者和消费者之间的协调。 进程互斥:在同一时刻,只允许一个进程访问共享资源,以避免数据冲突或错误。通过互斥机制(如互斥锁),我们可以防止多个进程同时访问同一资源,确保数据一致性。 2. 信号量 信号量是一种用于解决进程同步和互斥问题的低级机制。它是一种计数器,用于控制对共享资源的访问。信号量有两种类型: 1. 二进制信号量Mutex:表示只有两个状态(锁定和解锁),主要用于实现进程互斥。通过互斥锁,确保在某一时刻仅有一个线程可以进入临界区。 2. 计数信号量:允许多个线程同时访问共享资源,通常用于实现资源计数(如缓冲区的空位和满位)。在本次实验中,使用两个信号量 empty 和 full 来分别表示缓冲区的空槽位和满槽位。 3. 生产者-消费者问题 生产者-消费者问题是经典的进程同步问题,其中包括两种进程: 生产者:负责生成产品并将其放入缓冲区。 消费者:负责从缓冲区中消费产品。 描述过程如下: 1. 当生产者试图生产产品时,它需要检查缓冲区是否有空位。如果没有空位,生产者将等待(即调用 sem_wait(&empty))。 2. 当生产者成功生产一个产品后,它将把产品放入缓冲区中的特定位置,并更新生产者的指针。接着,它会释放一个 full 信号量,以通知消费者缓冲区中有新的产品可供消费(即调用 sem_post(&full))。 3. 消费者在消费产品时,首先检查缓冲区是否有可消费的产品。如果没有可消费的产品,它将等待(即调用 sem_wait(&full))。 4. 消费者从缓冲区中取出一个产品,更新消费者指针,并释放一个 empty 信号量,以通知生产者缓冲区中的空位可用(即调用 sem_post(&empty))。 |

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 5. 实验过程或源代码 #include <stdio.h> #include <pthread.h> #include <semaphore.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #define BUFFER_SIZE 6 // 缓冲区大小 #define NUM_ITEMS 20 // 每个生产者和消费者要处理的产品数量 typedef struct { int buffer[BUFFER_SIZE]; int in; // 生产者指针 int out; // 消费者指针 } CircularBuffer; CircularBuffer cb; sem_t empty; // 空槽位信号量 sem_t full; // 满槽位信号量 pthread_mutex_t mutex; // 互斥锁 // 生产者线程函数 void* producer(void* name) { char* thread_name = (char*)name; // 将参数转为字符串 for (int i = 0; i < NUM_ITEMS; i++) { sleep(rand() % 2); // 模拟生产过程 int item = i; // 生产的产品标识符是i sem_wait(&empty); // 等待空槽位 pthread_mutex_lock(&mutex); // 进入临界区 // 放入缓冲区 cb.buffer[cb.in] = item; // 计算当前的产品数量 int current_count = (cb.in + 1 - cb.out + BUFFER_SIZE) % BUFFER_SIZE; if(!current_count) current_count=6; printf("%s produced: %d, Buffer Count: %d, Position: %d\n", thread_name, item, current_count, cb.in); cb.in = (cb.in + 1) % BUFFER_SIZE; // 更新生产者指针 pthread_mutex_unlock(&mutex); // 退出临界区 sem_post(&full); // 增加满槽位 } return NULL; } // 消费者线程函数 void* consumer(void* name) { char* thread_name = (char*)name; // 将参数转为字符串 for (int i = 0; i < NUM_ITEMS; i++) { sleep(rand() % 2); // 模拟消费过程 sem_wait(&full); // 等待满槽位 pthread_mutex_lock(&mutex); // 进入临界区 // 从缓冲区取出产品 int item = cb.buffer[cb.out]; // 计算当前的产品数量 int current_count = (cb.in - cb.out - 1 + BUFFER_SIZE) % BUFFER_SIZE; printf("%s consumed: %d, Buffer Count: %d, Position: %d\n", thread_name, item, current_count, cb.out); cb.out = (cb.out + 1) % BUFFER_SIZE; // 更新消费者指针 pthread_mutex_unlock(&mutex); // 退出临界区 sem_post(&empty); // 增加空槽位 } return NULL; } int main() { // 初始化缓冲区 cb.in = 0; cb.out = 0; sem_init(&empty, 0, BUFFER_SIZE); // 初始化空槽位信号量 sem_init(&full, 0, 0); // 初始化满槽位信号量 pthread_mutex_init(&mutex, NULL); // 初始化互斥锁 pthread_t producers[2]; // 多个生产者线程 pthread_t consumers[2]; // 多个消费者线程 // 启动生产者线程,传入线程名字 char* producer_names[2] = {"P1", "P2"}; for (int i = 0; i < 2; i++) { pthread_create(&producers[i], NULL, producer, (void*)producer_names[i]); } // 启动消费者线程,传入线程名字 char* consumer_names[2] = {"C1", "C2"}; for (int i = 0; i < 2; i++) { pthread_create(&consumers[i], NULL, consumer, (void*)consumer_names[i]); } // 等待生产者线程结束 for (int i = 0; i < 2; i++) { pthread_join(producers[i], NULL); } // 等待消费者线程结束 for (int i = 0; i < 2; i++) { pthread_join(consumers[i], NULL); } // 清理资源 sem_destroy(&empty); sem_destroy(&full); pthread_mutex_destroy(&mutex); return 0; } |
| 6 .实验结果 实验结果如图1所示,一共启动了4个线程(生产者:P1,P2;消费者:C1,C2),每个进程按规则(代码)随机抢占,produced:每个线程第i次抢占到缓冲区,Buffer Count:表示当前缓冲区有几个产品,Position表示当前缓冲区存放/消费产品的位置。 图1 |

相关推荐
weixin_421922692 小时前
C++中的状态模式高级应用
开发语言·c++·算法
楼田莉子2 小时前
Linux网络:应用层HTTP网络协议
网络·c++·后端·网络协议·学习·http
二年级程序员2 小时前
认识与了解 C++
开发语言·c++
TsukasaNZ2 小时前
代码性能剖析工具
开发语言·c++·算法
Trouvaille ~2 小时前
【项目篇】从零手写高并发服务器(五):Channel事件管理与Poller模块
运维·服务器·c++·reactor·高并发·多路转接·epoll
dapeng28702 小时前
C++中的观察者模式变体
开发语言·c++·算法
khddvbe2 小时前
分布式日志系统实现
开发语言·c++·算法
yuyanjingtao2 小时前
CCF-GESP 等级考试 2026年3月认证C++一级真题解析
c++·算法·青少年编程·gesp·csp-j/s
2401_891482173 小时前
C++中的代理模式实战
开发语言·c++·算法