进程(线程)同步和互斥实验报告
操 作 系 统 实 验 报 告 课程名称
操作系统
实验名称
进程(线程)的同步与互斥
成绩
学生姓名
作业君
专业
软件工程
班级、学号
同组者姓名
无
实验日期
2020
一、实验题目: : 进程(线程)的同步与互斥 二、实验目的 :
自行编制模拟程序,通过形象化的状态显示,加深理解进程的概念、进程之间的状态转换及其所带来的 PCB 内容 、组织的变化,理解进程与其 PCB 间的一一对应关系。
1.掌握基本的同步与互斥算法,理解生产者消费者模型。
2.学习使用 Windows 中基本的同步对象,掌握相关 API 的使用方法。
3.了解 Windows 中多线程的并发执行机制,实现进程的同步与互斥 三、实验内容与要求 :
1.实验内容 以生产者/消费者模型为依据,在 Windows 环境下创建一个控制台进程,在该进程中创建 n 个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
2.实验要求 学习并理解生产者/消费者模型及其同步/互斥规则; 学习了解 Windows 同步对象及其特性; 熟悉实验环境,掌握相关 API 的使用方法; 设计程序,实现生产者/消费者进程(线程)的同步与互斥;
四、算法描述(含数据结构定义)或流程图
#include <Windows.h> #include <iostream> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std;
#define MAX_THREAD_NUM 64
//最大线程数 #define INTE_PER_SEC 1000
//延迟时间的毫秒值 const int SIZE_OF_BUFFER = 10;
//缓冲区长度 int ProductID = 0;
//产品号 int ConsumeID = 0;
//将被消耗的产品号 int in = 0;
//产品进缓冲区时的缓冲区下标 int out = 0;
//产品出缓冲区时的缓冲区下标 bool running = true;
//判断程序能否继续执行的逻辑值 int g_buffer[SIZE_OF_BUFFER];
//缓冲区是个循环队列 HANDLE g_hMutex;
//公有信号量,用于线程间的互斥 HANDLE g_hFullSemaphore;
//生产者的私有信号量,当缓冲区满时迫使生产者等待 HANDLE g_hEmptySemaphore;
//消费者的私有信号量,当缓冲区空时迫使消费者等待
//定义一个结构体用于存储线程的信息 struct ThreadInfo {
int serial;
//线程号
char entity;
//线程类别(生产者或消费者)
double delay;
//等待时间
double persist; //操作时间 };
//生产者 void Producer(void* p) {
//定义变量用于存储当前线程的信息
DWORD m_delay;
DWORD m_persist;
int m_serial;
//从参数中获得信息
m_serial = ((ThreadInfo*)(p))->serial;
m_delay = (DWORD)(((ThreadInfo*)(p))->delay * INTE_PER_SEC);
m_persist = (DWORD)(((ThreadInfo*)(p))->persist * INTE_PER_SEC);
while (running)
{
//P 操作
cout << "生产者线程 " << m_serial << " 请求生产." << endl;
WaitForSingleObject(g_hEmptySemaphore, INFINITE);
cout << "生产者线程 " << m_serial << " 请求独占缓冲区." << endl;
WaitForSingleObject(g_hMutex, INFINITE);
Sleep(m_delay);
//延迟等待
//生产一个产品
cout << "生产者线程 " << m_serial << " 生产 " << ++ProductID << " 号产品成功." << endl;
cout << "生产者线程 " << m_serial << " 请求将产品 " << ProductID << " 投入缓冲区." << endl;
//把新生产的产品放入缓冲区
g_buffer[in] = ProductID;
in = (in +1)%SIZE_OF_BUFFER;
Sleep(m_persist);
//操作等待
cout << "生产者线程 " << m_serial << " 将产品 " << ProductID << " 投入缓冲区中成功." << endl;
//输出缓冲区当前的状态
cout << "****************************" << endl
<< "\n 当前缓冲区情况如图(■代表已有产品,□代表没有产品):
" << endl;
for (int i = 0;i < SIZE_OF_BUFFER;++i)
{
if (g_buffer[i] != 0)
cout << "■";
else
cout << "□";
}
cout << "\n\n****************************\n" << endl;
//V 操作
ReleaseMutex(g_hMutex);
ReleaseSemaphore(g_hFullSemaphore, 1, NULL);
} }
//消费者 void Consumer(void* p) {
DWORD m_delay;
DWORD m_persist;
int m_serial;
//从参数中获得信息
m_serial = ((ThreadInfo*)(p))->serial;
m_delay = (DWORD)(((ThreadInfo*)(p))->delay * INTE_PER_SEC);
m_persist = (DWORD)(((ThreadInfo*)(p))->persist * INTE_PER_SEC);
while (running)
{
//P 操作
cout << "消费者线程 " << m_serial << " 请求消费." << endl;
WaitForSingleObject(g_hFullSemaphore, INFINITE);
cout << "消费者线程 " << m_serial << " 请求独占缓冲区." << endl;
WaitForSingleObject(g_hMutex,INFINITE);
Sleep(m_delay); //延迟等待
//从缓冲区中取出一个产品
cout << "消费者线程 " << m_serial << " 请求取出一个产品." << endl;
ConsumeID = g_buffer[out];
g_buffer[out] = 0;
out = (out + 1) % SIZE_OF_BUFFER;
cout << "消费者线程 " << m_serial << " 取出产品 " << ConsumeID << " 成功." << endl;
//消耗一个产品
cout << "消费者线程 " << m_serial << " 开始消费消费产品 " << ConsumeID << "." << endl;
Sleep(m_persist);
cout << "消费者线程 " << m_serial << " 消费产品 " << ConsumeID << " 成功." << endl;
//输出缓冲区当前的状态
cout << "****************************" << endl
<< "\n 当前缓冲区情况如图:
" << endl;
for (int i = 0;i < SIZE_OF_BUFFER;++i)
{
if (g_buffer[i] != 0)
cout << "■";
else
cout << "□";
}
cout << "\n\n****************************\n" << endl;
//V 操作
ReleaseMutex(g_hMutex);
ReleaseSemaphore(g_hEmptySemaphore, 1, NULL);
} }
void prod_cons() {
//创建互斥信号量
g_hMutex = CreateMutex(NULL, FALSE, NULL);
//创建同步信号量
g_hEmptySemaphore = CreateSemaphore(NULL, SIZE_OF_BUFFER, SIZE_OF_BUFFER, NULL);
g_hFullSemaphore = CreateSemaphore(NULL, 0, SIZE_OF_BUFFER, NULL);
srand((unsigned)time(NULL));
//以时间函数为种子
const unsigned short THREADS_COUNT = rand() % 5 + 5; //总的线程数(随机生成)
//线程对象的数组
HANDLE hThreads[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];
DWORD thread_ID; //线程 ID
int num = 0;
//临时变量,用于循环语句
cout << "系统开始模拟,并自动生成模拟数据..." << endl;
system("pause"); //暂停确认开始执行
cout << "线程总数:" << THREADS_COUNT << endl;
//循环随机生成各个线程的信息
while (num != THREADS_COUNT)
{
thread_info[num].serial = num + 1;
if (rand() % 2 == 1)
thread_info[num].entity = "P";
else
thread_info[num].entity = "C";
thread_info[num].delay = rand() % 5 + 1;
thread_info[num].persist = rand() % 6 + 2;
num++;
}
cout << "\n 系统生成数据结束,模拟数据如下:" << endl
<< "线程号
线程类别
延迟时间
操作时间" << endl;
for (int x = 0;x < THREADS_COUNT;x++)
cout << "
" << thread_info[x].serial << "\t"
<< "
" << thread_info[x].entity << "\t"
<< "
" << thread_info[x].delay << "\t\t"
<< "
" << thread_info[x].persist << endl;
cout << "\n\n==================生产者-消费者 开始==================\n" << endl;
//创建线程
for (int i = 0;i < THREADS_COUNT;i++)
{
//创建生产者线程
if (thread_info[i].entity == "P")
hThreads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(Producer), &thread_info[i], 0, &thread_ID);
//创建消费者线程
else
hThreads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(Consumer), &thread_info[i], 0, &thread_ID);
}
while (running)
{
if (getchar())
{
//按回车后终止程序运行
running = false;
}
}
cout << "系统模拟结束..." << endl; } int main() {
cout << "\n==================生产者-消费者 模拟==================\n" << endl;
prod_cons(); }
五、实验过程
1、记录生产者和消费者的同步执行过程。
2、分析 Producer 函数和 Consumer 函数的功能,并画出对应的程序流程图。
Producer 函数:调用函数,获取资源情况,然后判断条件是否满足,判断是否执行,接着发出生产请求,请求通过后独占缓冲区资源,接着生产-一个产品投入缓冲区,成功后释放所占缓冲区资源,到此此函数执行完成。
consumer 函数:
通过用变量提取保存提取当前资源信息, 然后判断是否执行, 接着发出消费请求, 请求通过后独占缓冲区资源, 接着消费一个产品取出缓冲区, 成功后释放所占缓冲区资源, 到此此函数执行完成。
3、试将同步和互斥的 P 操作颠倒次序执行,观察并分析程序的运行情况。
答:
如将同步和互斥的 P 操作颠倒次序执行,程序会产生死锁。因为这个操作会先独占缓冲区的资源,然后才发送请求。如果生产或者消费请求无法通过而一直等待下去的话,则无法释放资源,进而产生程序的死锁,使得程序无法运行!
六、实验总结
通过本次实验,让我对线程的同步与互斥技术有了比较深刻的了解,生产者消费者问题是研究多线线程程序绕不开的问题,它的描述是有一块生产者和消费者共享的有界缓冲区,生产者往缓冲区放入产品,消费者从缓冲区取走产品,这个过程可以无休止的进行,不能因缓冲区满生产者放不进产品而终止,也不能因缓冲区空消费者无产品可取而终止。
上一篇:扶贫学习考察调研报告x
下一篇:房产公司诚信经营企业申报材料