IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 华中科技大学操作系统实验课 实验二 -> 正文阅读

[系统运维]华中科技大学操作系统实验课 实验二

一、实验目的

  • (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下创建一对父子进程。

  • 提示 1:分别输出各自的进程号,父进程号和特别的提示字符串信息
  • 提示 2:让父进程提前结束或后结束,观察子进程的父进程 ID。
  • 提示 3:使用 PS 命令查看进程列表信息,核对进程号,父进程号
#include<unistd.h>
#include<stdio.h>
int main()
{
	pid_t p1=fork();
	if(p1>0){
		printf(" 父进程进程号:%d\n",getpid());
                printf(" 创建的子进程进程号:%d\n",p1);
		printf(" 暂时挂起父进程以便ps检查结果(10s):\n");
		sleep(2);
		printf(" 父进程结束\n");
	}else{
		printf(" 子进程进程号:%d\n",getpid());
		printf(" 父进程未结束时,子进程的父进程进程号:%d\n",getppid());
		sleep(4);
		printf(" \n父进程结束后,子进程的父进程进程号:%d\n",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 <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

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

//定义线程2运行函数
void* th_fn2(void *arg) //传入void*数值 r
{
	for(int i=1000;i>0;i--){
		printf("B:%d\n",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 <iostream>
#include <thread>
#include <windows.h>

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<iostream>
#include <thread>

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 <stdio.h>
#include <windows.h>
#include <time.h>
#include <string>


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开始思考,将思考%dms\n", id, time);
		Sleep(time);
		time = random();
		printf("哲学家%d开始休息,将休息%dms\n", id, time);
		Sleep(time);
		//p(left)
		WaitForSingleObject(left, INFINITE);
		printf("哲学家%d取了左手边的筷子\t%d\n", id, id);
		//p(right)
		WaitForSingleObject(right, INFINITE);
		printf("哲学家%d取了右手边的筷子\t%d\n", id, (id + 4) % 5);
		//吃饭
		time = random();
		printf("哲学家%d开始吃饭,将吃饭%dms\n", id, time);
		Sleep(time);
		//v
		ReleaseSemaphore(left, 1, NULL);
		printf("哲学家%d放下左手边的筷子\t%d\n", id, id);
		ReleaseSemaphore(right, 1, NULL);
		printf("哲学家%d放下右手边的筷子\t%d\n", 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%d\n", id, id);
			//p(right)
			WaitForSingleObject(right, INFINITE);
			printf("哲学家%d取了右手边的筷子\t%d\n", id, (id + 4) % 5);
		}
		else {//先取右边的筷子
			//p(right)
			WaitForSingleObject(right, INFINITE);
			printf("哲学家%d取了右手边的筷子\t%d\n", id, (id + 4) % 5);
			//p(left)
			WaitForSingleObject(left, INFINITE);
			printf("哲学家%d取了左手边的筷子\t%d\n", id, id);
		}

完整代码

#undef UNICODE
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <string>


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开始思考,将思考%dms\n", id, time);
		Sleep(time);
		time = random();
		printf("哲学家%d开始休息,将休息%dms\n", id, time);
		Sleep(time);

		if (id == 0) {//先取左边的筷子
			//p(left)
			WaitForSingleObject(left, INFINITE);
			printf("哲学家%d取了左手边的筷子\t%d\n", id, id);
			//p(right)
			WaitForSingleObject(right, INFINITE);
			printf("哲学家%d取了右手边的筷子\t%d\n", id, (id + 4) % 5);
		}
		else {//先取右边的筷子
			//p(right)
			WaitForSingleObject(right, INFINITE);
			printf("哲学家%d取了右手边的筷子\t%d\n", id, (id + 4) % 5);
			//p(left)
			WaitForSingleObject(left, INFINITE);
			printf("哲学家%d取了左手边的筷子\t%d\n", id, id);
		}
		
		//吃饭
		time = random();
		printf("哲学家%d开始吃饭,将吃饭%dms\n", id, time);
		Sleep(time);
		//v
		ReleaseSemaphore(left, 1, NULL);
		printf("哲学家%d放下左手边的筷子\t%d\n", id, id);
		ReleaseSemaphore(right, 1, NULL);
		printf("哲学家%d放下右手边的筷子\t%d\n", 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 <stdio.h>
#include <windows.h>
#include <time.h>
#include <string>


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开始思考,将思考%dms\n", id, time);
		Sleep(time);
		time = random();
		printf("哲学家%d开始休息,将休息%dms\n", id, time);
		Sleep(time);
	
		//p
		WaitForMultipleObjects(2, chops, true, INFINITE);//true表面只有等待所有信号量有效时,再往下执行。(FALSE 当有其中一个信号量有效时就向下执行)
		printf("哲学家%d同时取了两边的筷子\t%d,%d\n", id, id, (id + 4) % 5);

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

		//v
		ReleaseSemaphore(chops[0], 1, NULL);
		printf("哲学家%d放下左手边的筷子\t%d\n", id, id);
		ReleaseSemaphore(chops[1], 1, NULL);
		printf("哲学家%d放下右手边的筷子\t%d\n", 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]);
	}
}


在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 13:09:20  更:2022-05-09 13:11:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 18:41:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码