栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

华中科技大学操作系统实验课 实验二

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

华中科技大学操作系统实验课 实验二

一、实验目的
  • (1)理解进程/线程的概念和应用编程过程;
  • (2)理解进程/线程的同步机制和应用编程;
二、实验内容
  • 1)在Linux下创建一对父子进程。
  • 2)在Linux下创建2个线程A和B,循环输出数据或字符串。
  • 3)在Windows下创建线程A和B,循环输出数据或字符串。
  • 4)在Linux下创建一对父子进程,实验wait同步函数。
  • 5)在Windows下利用线程实现并发画圆/画方。
  • 6)在Windows或Linux下利用线程实现“生产者-消费者”同步控制
  • 7)在Linux下利用信号机制实现进程通信。
  • 8)在Windows或Linux下模拟哲学家就餐,提供死锁和非死锁解法。
三、实验要求
  • 2,6,8必做,其余任选2。课前提前预做,老师机房检查和答疑

文章目录
  • 一、实验目的
  • 二、实验内容
  • 三、实验要求
  • 实验一,在Linux下创建一对父子进程。
  • 实验二,在Linux下创建2个线程A和B,循环输出数据或字符串
    • 1.编写代码
    • 2.编译运行
    • 3.结果
  • 实验三、在Windows下创建线程A和B,循环输出数据或字符串。
  • 实验六、在Windows或Linux下利用线程实现“生产者-消费者”同步控制
  • 实验八、在Windows或Linux下模拟哲学家就餐,提供死锁和非死锁解法。
    • 会导致死锁的算法
    • 不会导致死锁的算法
    • 完全不可能产生死锁的解法

实验一,在Linux下创建一对父子进程。
  • 提示 1:分别输出各自的进程号,父进程号和特别的提示字符串信息
  • 提示 2:让父进程提前结束或后结束,观察子进程的父进程 ID。
  • 提示 3:使用 PS 命令查看进程列表信息,核对进程号,父进程号
#include
#include
int main()
{
	pid_t p1=fork();
	if(p1>0){
		printf(" 父进程进程号:%dn",getpid());
                printf(" 创建的子进程进程号:%dn",p1);
		printf(" 暂时挂起父进程以便ps检查结果(10s):n");
		sleep(2);
		printf(" 父进程结束n");
	}else{
		printf(" 子进程进程号:%dn",getpid());
		printf(" 父进程未结束时,子进程的父进程进程号:%dn",getppid());
		sleep(4);
		printf(" n父进程结束后,子进程的父进程进程号:%dn",getppid());
		printf(" 子进程结束n");
	}
	return 0;
}



编译运行

 gcc ./test.c -o test1.out
 ./test1.out

结果

使用 PS 命令查看进程列表信息,核对进程号,父进程号

ps -o pid,ppid,cmd

为什么没有./test1.out我也不知道!!!毁灭吧!

ps -ef|grep test1.out

实验二,在Linux下创建2个线程A和B,循环输出数据或字符串
  • 提示 1:使用 pthread 线程库
  • 提示 2:线程 A 递增输出 1-1000;线程 B 递减输出 1000-1。为避免输出太快,每隔 0.2 秒(可自行调节)输出一个数。
  • 提示 3:输出数据时,同时输出 A 或 B 以标示是哪个线程输出的,并注意格式化输出信息。
1.编写代码
#include 
#include 
#include 
#include 

//定义线程1运行函数
void* th_fn1(void *arg) //传入void*数值 a
{
	for(int i=1;i<=1000;i++){
		printf("A:%dn",i);
		sleep(1);
	}
}

//定义线程2运行函数
void* th_fn2(void *arg) //传入void*数值 r
{
	for(int i=1000;i>0;i--){
		printf("B:%dn",i);
		sleep(1);
	}
}

int main()
{
	int err;//定义错误存储
   	pthread_t  tid1,tid2;//定义线程标识符

   	//创建tid1线程
   	if(err=pthread_create(&tid1,NULL,th_fn1,NULL)){
		perror("pthread_create error");
	}


   	//创建tid2线程
   	if(err=pthread_create(&tid2,NULL,th_fn2,NULL)){
		perror("pthread_create error");
	}
	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	return 0;
}

2.编译运行

注意要加入-lpthread,才能使用线程。因为 pthread_create 等线程函数不在 C 标准库中。

gcc ./test2.c -o ./test2.out -lpthread
3.结果

实验三、在Windows下创建线程A和B,循环输出数据或字符串。
  • 提示 1:使用 CreateThread 创建线程
  • 提示 2:线程 A 递增输出 1-1000;线程 B 递减输出 1000-1。为避免输出太快,每隔 0.2 秒输出一个数。
  • 提示 3:输出数据时,同时输出 A 或 B 标示是哪个线程输出的,并注意格式化输出信息

老师方法的代码

#include 
#include 
#include 

DWORD WINAPI add(LPVOID)
{
	for (int i = 1; i<=1000; i++) {
		std::cout << "A:" << i << std::endl;
		Sleep(5);
	}
	return 1;
}


DWORD WINAPI dec(PVOID pParam) {
	for (int i = 1000; i > 0; i--) {
		std::cout << "B:" << i << std::endl;
		Sleep(5);
	}

	return 0;
}

int main() {

	HANDLE hthread[2];
	DWORD threadID;
	DWORD threadID1;
	hthread[0] = CreateThread(NULL, 0, add, (LPVOID)1, 0, &threadID);
	hthread[1] = CreateThread(NULL, 0, dec, (LPVOID)2, 0, &threadID1);
	WaitForMultipleObjects(2, hthread, TRUE, INFINITE);
	return 0;
}

运行结果

从 C++11 开始,线程,成为了 C++ 标准库的一部分,所以我们可以不再使用 CreateThread 来创建线程,简简单单地使用 std::thread 即可。

而且,CreateThread 是平台相关的,而 std::thread 是跨平台的。
因此,干嘛用CreateThread 。

使用std::thread的代码

#include
#include 

void func_1() {
	for (int i = 1; i <= 1000; i++) {
		std::cout << i << std::endl;
	}
}

void func_2() {
	for (int i = 1000; i > 0; i--) {
		std::cout << i << std::endl;
	}
}


int main() {
	std::thread t1(func_1);
	std::thread t2(func_2);
	t1.join();
	t2.join();

	return 0;
}

运行结果

实验六、在Windows或Linux下利用线程实现“生产者-消费者”同步控制
  • 提示 1:使用数组(10 个元素)代替缓冲区。2 个输入线程产生产品(随机数)存到数组中;3 个输出线程从数组中取数输出。
  • 提 示 2 : Windows 使 用 临 界 区 对 象 和 信 号 量 对 象 , 主 要 函 数EnterCriticalSection() 、 LeaveCriticalSection() 、 WaitForSingleObject() 、ReleaseSemaphore()。
  • 提示 3:Linux 使用互斥锁对象和轻量级信号量对象,主要函数:sem_wait( ),sem_post( ),pthread_mutex_lock( ),pthread_mutex_unlock( )。
  • 提示 4:生产者 1 的数据:1000-1999 (每个数据随机间隔 100ms-1s),生产者 2 的数据:2000-2999 (每个数据随机间隔 100ms-1s)。
  • 提示 5:消费者每休眠 100ms-1s 的随机时间消费一个数据。
  • 提示 6:屏幕打印(或日志文件记录)每个数据的生产和消费记录。

抄别人作业就好

Windows下模拟生产者消费者问题 使用Windows.h库下实现

《操作系统实验》C++实现生产者-消费者问题使用c++标准库实现

对于个人来说,使用第二种方法
结果截图:

实验八、在Windows或Linux下模拟哲学家就餐,提供死锁和非死锁解法。
  • 提示 1:同时提供提供可能会带来死锁的解法和不可能死锁的解法。
  • 提示 2:可能会带来死锁的解法参⻅课件。Windows 尝试使用临界区对象( EnterCriticalSection , LeaveCriticalSection ) ; Linux 尝 试 使 用 互 斥 锁(pthread_mutex_lock, pthread_mutex_unlock)
  • 提示 3:完全不可能产生死锁的解法,例如:尝试拿取两只筷子,两只都能拿 则 拿 , 否 则 都 不 拿 。 Windows 尝 试 使 用 WaitForMultipleObjects, WaitForSingleObject 和互斥量对象 ReleaseMutex 等相关函数) Linux 尝试使用互斥锁 pthread_mutex_lock,pthread_mutex_trylock 等函数。
  • 提示 4:[可选] 图形界面显示哲学家取筷,吃饭,放筷,思考等状态。
  • 提示 5:为增强随机性,各状态间维持 100ms-500ms 内的随机时⻓。

借鉴博客:操原上机(三) 哲学家就餐问题的死锁与非死锁解法

会导致死锁的算法
#undef UNICODE
#include 
#include 
#include 
#include 


int i = 0;
std::string name[5] = { "0","1","2","3","4" };
int a[5] = { 1,1,1,1,1 };
int random(void) {
	int a = time(NULL);
	srand(a);
	return (rand() % 400 + 100);
}
//子线程函数  
DWORD WINAPI philosopher(LPVOID lpParam) {
	int id = i++;
	int time;
	HANDLE right, left;
	left = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, name[id].c_str());//通过信号量名,获得信号量对象句柄
	right = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, name[(id + 4) % 5].c_str());
	while (1) {
		time = random();
		printf("哲学家%d开始思考,将思考%dmsn", id, time);
		Sleep(time);
		time = random();
		printf("哲学家%d开始休息,将休息%dmsn", id, time);
		Sleep(time);
		//p(left)
		WaitForSingleObject(left, INFINITE);
		printf("哲学家%d取了左手边的筷子t%dn", id, id);
		//p(right)
		WaitForSingleObject(right, INFINITE);
		printf("哲学家%d取了右手边的筷子t%dn", id, (id + 4) % 5);
		//吃饭
		time = random();
		printf("哲学家%d开始吃饭,将吃饭%dmsn", id, time);
		Sleep(time);
		//v
		ReleaseSemaphore(left, 1, NULL);
		printf("哲学家%d放下左手边的筷子t%dn", id, id);
		ReleaseSemaphore(right, 1, NULL);
		printf("哲学家%d放下右手边的筷子t%dn", id, (id + 4) % 5);
	}
}
int main(void) {
	HANDLE S[5]; //五个信号量
	HANDLE hThread[5]; //五个线程
	for (int i = 0; i < 5; i++) {
		S[i] = CreateSemaphore(NULL, 1, 1, name[i].c_str());
	}

	for (int i = 0; i < 5; i++) {
		hThread[i] = CreateThread(NULL, 0, philosopher, NULL, 0, NULL);
	}
	WaitForMultipleObjects(5, hThread, TRUE, INFINITE); 	//等待子线程运行 
	for (int i = 0; i < 5; i++) {
		CloseHandle(S[i]);
	}
}

出现死锁

不会导致死锁的算法

修改代码

		if (id == 0) {//先取左边的筷子
			//p(left)
			WaitForSingleObject(left, INFINITE);
			printf("哲学家%d取了左手边的筷子t%dn", id, id);
			//p(right)
			WaitForSingleObject(right, INFINITE);
			printf("哲学家%d取了右手边的筷子t%dn", id, (id + 4) % 5);
		}
		else {//先取右边的筷子
			//p(right)
			WaitForSingleObject(right, INFINITE);
			printf("哲学家%d取了右手边的筷子t%dn", id, (id + 4) % 5);
			//p(left)
			WaitForSingleObject(left, INFINITE);
			printf("哲学家%d取了左手边的筷子t%dn", id, id);
		}

完整代码

#undef UNICODE
#include 
#include 
#include 
#include 


int i = 0;
std::string name[5] = { "0","1","2","3","4" };
int a[5] = { 1,1,1,1,1 };
int random(void) {
	int a = time(NULL);
	srand(a);
	return (rand() % 400 + 100);
}
//子线程函数  
DWORD WINAPI philosopher(LPVOID lpParam) {
	srand((unsigned)time(NULL));
	int id = i++;
	int time;
	HANDLE right, left;
	left = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, name[id].c_str());//通过信号量名,获得信号量对象句柄
	right = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, name[(id + 4) % 5].c_str());
	while (1) {
		time = random();
		printf("哲学家%d开始思考,将思考%dmsn", id, time);
		Sleep(time);
		time = random();
		printf("哲学家%d开始休息,将休息%dmsn", id, time);
		Sleep(time);

		if (id == 0) {//先取左边的筷子
			//p(left)
			WaitForSingleObject(left, INFINITE);
			printf("哲学家%d取了左手边的筷子t%dn", id, id);
			//p(right)
			WaitForSingleObject(right, INFINITE);
			printf("哲学家%d取了右手边的筷子t%dn", id, (id + 4) % 5);
		}
		else {//先取右边的筷子
			//p(right)
			WaitForSingleObject(right, INFINITE);
			printf("哲学家%d取了右手边的筷子t%dn", id, (id + 4) % 5);
			//p(left)
			WaitForSingleObject(left, INFINITE);
			printf("哲学家%d取了左手边的筷子t%dn", id, id);
		}
		
		//吃饭
		time = random();
		printf("哲学家%d开始吃饭,将吃饭%dmsn", id, time);
		Sleep(time);
		//v
		ReleaseSemaphore(left, 1, NULL);
		printf("哲学家%d放下左手边的筷子t%dn", id, id);
		ReleaseSemaphore(right, 1, NULL);
		printf("哲学家%d放下右手边的筷子t%dn", id, (id + 4) % 5);
	}
}
int main(void) {
	HANDLE S[5]; //五个信号量
	HANDLE hThread[5]; //五个线程
	for (int i = 0; i < 5; i++) {
		S[i] = CreateSemaphore(NULL, 1, 1, name[i].c_str());
	}

	for (int i = 0; i < 5; i++) {
		hThread[i] = CreateThread(NULL, 0, philosopher, NULL, 0, NULL);
	}
	WaitForMultipleObjects(5, hThread, TRUE, INFINITE); 	//等待子线程运行 
	for (int i = 0; i < 5; i++) {
		CloseHandle(S[i]);
	}
}


运行结果未出现死锁

完全不可能产生死锁的解法

基本思想:只有当左右两边的筷子都可取时,同时取两边的筷子用餐。

#undef UNICODE
#include 
#include 
#include 
#include 


int i = 0;
std::string name[5] = { "0","1","2","3","4" };
int a[5] = { 1,1,1,1,1 };
int random(void) {
	int a = time(NULL);
	srand(a);
	return (rand() % 400 + 100);
}
//子线程函数  
DWORD WINAPI philosopher(LPVOID lpParam) {
	srand((unsigned)time(NULL));
	int id = i++;
	int time;
	HANDLE chops[2];
	chops[0] = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, name[id].c_str());
	chops[1] = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, name[(id + 4) % 5].c_str());
	while (1) {
		time = random();
		printf("哲学家%d开始思考,将思考%dmsn", id, time);
		Sleep(time);
		time = random();
		printf("哲学家%d开始休息,将休息%dmsn", id, time);
		Sleep(time);
	
		//p
		WaitForMultipleObjects(2, chops, true, INFINITE);//true表面只有等待所有信号量有效时,再往下执行。(FALSE 当有其中一个信号量有效时就向下执行)
		printf("哲学家%d同时取了两边的筷子t%d,%dn", id, id, (id + 4) % 5);

		//吃饭
		time = random();
		printf("哲学家%d开始吃饭,将吃饭%dmsn", id, time);
		Sleep(time);

		//v
		ReleaseSemaphore(chops[0], 1, NULL);
		printf("哲学家%d放下左手边的筷子t%dn", id, id);
		ReleaseSemaphore(chops[1], 1, NULL);
		printf("哲学家%d放下右手边的筷子t%dn", id, (id + 4) % 5);
	}
}
int main(void) {
	HANDLE S[5]; //五个信号量
	HANDLE hThread[5]; //五个线程
	for (int i = 0; i < 5; i++) {
		S[i] = CreateSemaphore(NULL, 1, 1, name[i].c_str());
	}

	for (int i = 0; i < 5; i++) {
		hThread[i] = CreateThread(NULL, 0, philosopher, NULL, 0, NULL);
	}
	WaitForMultipleObjects(5, hThread, TRUE, INFINITE); 	//等待子线程运行 
	for (int i = 0; i < 5; i++) {
		CloseHandle(S[i]);
	}
}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/871491.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号