【操作系统】进程的控制和通信

news2024/11/24 10:56:26

文章目录

  • 一. 实验目的
  • 二. 实验内容
  • 三. 实验步骤
  • 四. 实验结果

一. 实验目的

(1)加深对进程概念的理解,进一步认识并发执行的实质。
(2)掌握Linux 操作系统中进程的创建和终止操作。
(3)理解进程间通信的概念和方法。
(4)掌握常用的Linux 进程间通信的方法。

二. 实验内容

(1)编写一个C程序,并使用系统调用fork()创建一个子进程。要求如下:

① 在子进程中分别输出当前进程为子进程的提示、当前进程的PID 和父进程的PID、根据用户输入确定当前进程的返回值、退出提示等信息。
② 在父进程中分别输出当前进程为父进程的提示、当前进程的PID 和子进程的PID、等待子进程退出后获得的返回值、退出提示等信息。

(2)编写C程序,使用Linux中的IPC机制,完成 “石头、剪子、布”的游戏。

三. 实验步骤

(1)编写一个C程序,并使用系统调用fork()创建一个子进程。

程序设计

#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>

int main()
{
    pid_t childpid;
    int retval;
    int status;

    childpid=fork();
    if(childpid==0) // 子进程
    {
        printf("CHILD: I am the child process\n");
        printf("CHILD: My PID: %d\n", getpid());
        printf("CHILD: My parent's PID: %d\n", getppid());
        printf("CHILD: The value of fork return is: %d\n", childpid);
        printf("CHILD: Sleep for 1 second ..\n");

        sleep(1);

        printf("CHILD: Enter an exit value (0~255):");
        scanf("%d",&retval);
        printf("CHILD: Goodbye!\n");
        exit(retval);
    }
    else if(childpid>0) // 父进程
    {
        printf("PARENT: I am the parent process\n");
        printf("PARENT: My PID: %d\n", getpid());
        printf("PARENT: my child's PID:%d\n", childpid);
        printf("PARENT: I will now wait for my child to exit.\n");

        wait(&status);

        printf("PARENT: child's exit code is:%d\n",WEXITSTATUS(status));
        printf("PARENT: Goodbye\n");
        exit(0);
    }
    else // 错误处理
    {
        perror("fork error\n");
        exit(0);
    }

    return 0;
}

程序分析

该程序展示了一个父子进程之间的通信方式。它使用了fork()函数创建了子进程并在子进程中输出一些信息,最后子进程通过exit()函数返回一个退出值。在父进程中,它等待子进程的退出并通过wait()函数获取子进程退出的状态码。
首先是fork()函数的调用,它会返回一个值,该值有不同的含义:

  • 返回值为0时,表示当前进程是子进程。
  • 返回值大于0时,表示当前进程是父进程,返回值为子进程的PID。
  • 返回值小于0时,表示创建进程失败。

在子进程中,它会输出一些信息,包括它自己的PID和父进程的PID,以及fork()函数的返回值。然后,它会等待1秒钟,让父进程有时间执行并输出信息。接下来,它通过scanf()函数读取一个退出值,并通过exit()函数返回。
在父进程中,它会输出自己的PID和子进程的PID,并等待子进程退出。它通过wait()函数获取子进程退出时的状态码。wait()函数会阻塞当前进程,直到任意一个子进程退出。如果不关心哪个子进程退出,可以使用wait(NULL)。在该程序中,使用了&status来获取子进程退出的状态码,并通过WEXITSTATUS(status)函数获取子进程通过exit()函数返回的退出值。
最后,父进程输出子进程的退出值,并通过exit()函数退出进程。
总的来说,该程序展示了fork()函数创建子进程、子进程的输出、父进程等待子进程退出和获取子进程退出的状态码等基本操作。

(2)编写C程序,使用Linux中的IPC机制,完成 “石头、剪子、布”的游戏。

程序设计

#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>

#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

struct Game
{
        int Round;
	long Type;	
};

void result_send(int num)
{
	struct Game game;
	game.Type=1;
	game.Round= rand()%3;

	int ret=-1;
	
	ret=msgsnd(num,&game,sizeof(int),0);
	printf("%d msgsnd %d return %d\n",num,game.Round,ret);
	
}

int result_announce(int a,int b)
{
	if ((a+1==b) ||(a-2==b))
		return -1;
	else if(a==b)
		return 0;
	else
		return 1;
}
	
void writefile(int *result_list,int len)
{
	int count_A=0;
	int count_B=0;
	int pingju=0;

	FILE *fin;
	fin=fopen("result.txt","w");
	if(fin==NULL) 
		printf("This file wasn't opened");
	
	int i;
	for(i=0;i<len;i++)
	{
		switch(result_list[i])
		{
			case -1:
				count_A++;
				fprintf(fin,"No.%d: A win\n",i+1);
				printf("No.%d: A win\n",i+1);
				break;
			case 0:
				pingju++;
				fprintf(fin,"No.%d: end in a draw\n",i+1);
				printf("No.%d: end in a draw\n",i+1);
				break;
			case 1:
				count_B++;
				fprintf(fin,"No.%d: B win\n",i+1);
				printf("No.%d: B win\n",i+1);
				break;
		}
	}
	
	printf("\nThe final result is A win:%ds \nB win:%ds \nend in a draw %ds\n",count_A,count_B,pingju);
	fprintf(fin,"\nThe final result is A win: %ds \nB win: %ds \nend in a draw %ds\n",count_A,count_B,pingju);
	fclose(fin);
}

int main()
{
	int times;
	int key1=1234;
	int key2=5678;
	int *result_list;
	pid_t pid1,pid2;
	int msgid1,msgid2;

	msgid1=msgget(key1,IPC_CREAT | 0666);
	msgid2=msgget(key2,IPC_CREAT | 0666);
	if(msgid1==-1)
	{
		fprintf(stderr,"failed with error");
		exit(EXIT_FAILURE);
	}

	if(msgid2==-1)
	{
		fprintf(stderr,"failed with error");
		exit(EXIT_FAILURE);
	}

	printf("Game start, please input rounds:");
	scanf("%d",&times);
	printf("times=%d\n",times);
	result_list=(int*)malloc(times*sizeof(int));
	int i;
	for(i=0;i<times;i++)
	{
		printf("********i=%d********\n",i);
		pid1=fork();
		if(pid1==0)
		{
			//printf("in pid1:\n");
			int pid=getpid();
			printf("pid of pid1 is %d\n",pid);

			srand((unsigned)time(0)*3000);
			result_send(msgid1);
			exit(11);
		}
		

		pid2=fork();
		if(pid2==0)
		{
			//printf("in pid2:\n");
			int pid=getpid();
			printf("pid of pid2 is %d\n",pid);

			srand((unsigned)time(NULL)*i);
			result_send(msgid2);
			exit(22);
		}
		

		if(pid1<0 || pid2<0)
		{
			fprintf(stderr,"Fork Failed");
			printf("Fork failed!!");
			exit(-1);
		}
		else
		{
			//printf("in else before wait:\n");
			int status1,status2;			
			wait(&status1);
			//printf("wait1 ok, status1=%d\n",WEXITSTATUS(status1));

			wait(&status2);
			//printf("wait2 ok, status2=%d\n",WEXITSTATUS(status2));

			

			struct Game game1,game2;
			
			msgrcv(msgid1,&game1,sizeof(game1)-sizeof(long),0,0);
			printf("%d rcv %d ok\n",msgid1,game1.Round);

			msgrcv(msgid2,&game2,sizeof(game2)-sizeof(long),0,0);
			printf("%d rcv %d ok\n",msgid2,game2.Round);
			
			int j=result_announce(game1.Round,game2.Round);
			result_list[i]=j;
			printf("result_announce is %d.\n",j);
		}
		
	}//end for
	
	writefile(result_list,times);
	
	if(msgctl(msgid1,IPC_RMID,0)==-1)
		fprintf(stderr,"msgctl(IPC_RMID) failed\n");
	if(msgctl(msgid2,IPC_RMID,0)==-1)
		fprintf(stderr,"msgctl(IPC_RMID) failed\n");
	
	exit(EXIT_SUCCESS);
}

程序分析

该程序是一个石头剪刀布游戏的模拟,通过使用进程间通信机制实现了两个进程间的交互。程序创建了两个消息队列,分别用于进程1和进程2向其父进程发送消息,父进程接收消息并比较得出游戏结果,然后输出到文件中。以下是程序的详细分析:

首先定义了一个结构体Game,用于存储比赛的轮数和玩家出的手势,可以看作一个消息的格式。游戏结果用一个int型数组result_list来存储,其中0表示平局,-1表示A胜利,1表示B胜利。然后是result_send函数,它用于向指定的队列发送一条Game类型的消息。随机产生一个0~2的整数表示玩家出的手势,并设置Type为1表示这是来自进程1的消息。返回值表示发送操作是否成功。
result_announce函数用于比较两个玩家出的手势,返回值为0表示平局,-1表示A胜利,1表示B胜利。
writefile函数用于将游戏结果写入文件result.txt中,同时输出到控制台。其中count_A、count_B、pingju分别表示A胜利的次数、B胜利的次数和平局的次数。

在主函数中,首先创建了两个消息队列,然后询问玩家要进行多少轮游戏,并分配result_list数组的大小。进入for循环后,创建了两个子进程pid1和pid2,分别代表进程1和进程2。
在子进程中,通过调用srand()和result_send()函数来随机选择手势,然后向父进程所绑定的消息队列中发送一条消息。为了让每次产生的随机数不同,可以使用时间函数time()和进程id组合生成随机数的种子。
在父进程中,首先通过wait()函数等待子进程1和子进程2都结束,并获取它们退出时的状态值。然后使用msgrcv()函数从消息队列中接收子进程所发出的消息,也就是两个玩家出的手势。
接下来,调用result_announce()函数比较两个玩家出的手势,获取比赛结果,并将得到的结果保存到result_list数组中。
当所有的比赛都结束后,调用writefile()函数来输出结果到result.txt文件中,并输出到控制台。同时,通过msgctl()函数删除之前创建的两个消息队列。

总的来说,该程序运用了fork()函数创建子进程、消息队列实现进程间通信等基本操作。它模拟了石头剪刀布游戏的过程,同时也展示了使用进程间通信机制进行协作的思路。

四. 实验结果

(1)编写一个C程序,并使用系统调用fork()创建一个子进程。

1

(2)编写C程序,使用Linux中的IPC机制,完成 “石头、剪子、布”的游戏。

2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1147329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

公众号留言功能有必要开吗?如何开通留言?

为什么公众号没有留言功能&#xff1f;2018年2月12日&#xff0c;TX新规出台&#xff1a;根据相关规定和平台规则要求&#xff0c;我们暂时调整留言功能开放规则&#xff0c;后续新注册帐号无留言功能。这就意味着2018年2月12日号之后注册的公众号不论个人主体还是组织主体&…

【Java】HashMap集合

Map集合概述和使用 Map集合概述 Interface Map<k,v> k&#xff1a;键值类型 v&#xff1a;值的类型 Map集合的特点 键值对 映射关系 Key 和 Value一个键&#xff08;Key&#xff09;对应一个值&#xff08;Value&#xff09;键不允许重复&#xff0c;值可以重复如…

DXF文件写入多边形和名称属性,可在Global Mapper和ArcGIS打开

DXF文件写入多边形和名称属性&#xff0c;可在Global Mapper和ArcGIS打开 目标效果 为了实现下图的效果&#xff0c;学习了一下dxf格式的相关内容。 官方文档价值很高&#xff0c;但是结合实例.dxf文件看学习起来更快。 免费下载实例 下面将介绍dxf文件的格式规范&#xff0…

如何确保PCIe Gen3通道的信号质量

PCIe 3.0设计面对的挑战 PCIe由PCI-SIG协会研发和维护的一个高速标准接口&#xff0c;PCIe3.0是其开发的第三代接口高速差分接口&#xff0c;其单个差分对信号速率可到达8.0Gbps&#xff0c;目前其以广泛的应用于计算机服务器等设备领域。 下图显示的是一个典型的PCIe Gen3的…

高阶数据结构图下篇

目录&#xff1a; 图的基本概念二深度优先遍历&#xff08;DFS&#xff09;广度优先遍历&#xff08;BFS&#xff09; kruskal&#xff08;克鲁斯卡尔算法&#xff09;Prim&#xff08;普里姆算法&#xff09;Dijkstra(迪杰斯特拉算法)Bellman-ford(贝尔曼-福特算法) flyod-war…

为什么别人的vscode终端那么好看!!?

群友的terminal &#x1f431;: 在群里看到别人的vscode好好看&#xff0c;给我的也安排一下 &#x1f7e0;关键因素&#xff1a;oh my posh主题&#xff01;安装&#xff01; &#x1f431;: 但是装完打开powershell变慢了&#xff0c;大道至简&#xff01; 背景 系统&#x…

RSA ——Rational Structure Architecture r入门教程

&#xff08;一&#xff09;UML概述 UML&#xff0c;即统一建模语言&#xff08;Unified Modeling Language&#xff09;&#xff0c;是一种通用的面向对象的可视化建模语言。其核心目的是为软件的面向对象描述和建模提供一种标准化的方法。UML并不是一种编程语言&#xff0c;因…

【LLM】sft和pretrain数据处理和筛选方法

note 痛点&#xff1a;训练垂直领域模型&#xff0c;sft数据和增量pretrain数据质量把控很重要 当数据不够时&#xff0c;通过self-instruct等方法造多样化的数据当数据很多时&#xff0c;需要清洗/筛选出高质量数据 文章目录 note一、sft数据的筛选策略1.1 使用self-instruc…

华媒舍:日韩媒体发稿推广中8个关键因素帮助你实现突破

在当今经济全球化的时代背景下&#xff0c;日韩地域媒体影响力日益提高。对于需要在这一地区开展发稿推广的人来讲&#xff0c;掌握适度的思路和流程是十分重要的。下面我们就为大家介绍8个关键因素&#xff0c;以帮助你在日韩地域媒体发稿推广中实现突破。 1.科学研究行业在逐…

MySQL(2):环境搭建

1.软件下载 软装去官网下载&#xff08;社区版&#xff09;&#xff1a;https://downloads.mysql.com/archives/installer/&#xff08;历史版本可选&#xff09; 选择下面的&#xff0c;一步到位 2.软件安装 双击 .msi 文件 选完 Custom 自定义后点 next 按 1&#xff0c…

【LInux】进程概念II -- 描述进程

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法…感兴趣就关注我吧&#xff01;你定不会失望。 本篇导航 0. 进程概念1. 描述进程2. 组织进程 0. 进程概念 在初学阶段,我们对进程这个词仅在书上看见过,大多不太理解这个究竟是什么意思…

数据库管理-第113期 Oracle Exadata 04-硬件选择(20231020)

数据库管理-第113期 Oracle Exadata 04-硬件选择&#xff08;2023010290&#xff09; 本周没写文章&#xff0c;主要是因为到上海参加了Oracle CAB/PAB会议&#xff0c;这个放在后面再讲&#xff0c;本期讲一讲Exadata&#xff0c;尤其是存储节点的硬件选择及其对应的一些通用…

文件夹批量改名:如何在文件夹名左边添加递增的自动编号

在文件管理的过程中&#xff0c;我们有时需要对文件夹进行重命名&#xff0c;使其更具区分度和可读性。为了实现这一目标&#xff0c;我们可以采用在文件夹名左边添加递增的自动编号的方法。本文将介绍云炫文件管理器如何进行文件夹批量改名&#xff0c;以在文件夹名左边添加递…

如何将设计模式责任链模式运用到工作当中

文章目录 &#x1f31f; 如何将设计模式责任链模式运用到工作当中&#x1f34a; 什么是责任链模式&#x1f34a; 在工作中如何应用责任链模式&#x1f389; 权限验证&#x1f389; 日志记录&#x1f389; 数据处理 &#x1f34a; 责任链模式的优点&#x1f34a; 总结 &#x1f…

【MATLAB源码-第62期】基于蜣螂优化算法(DBO)的无人机三维地图路径规划,输出最短路径和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 蜣螂优化算法&#xff08;Dung Beetle Optimization, DBO&#xff09;是一种模拟蜣螂在寻找食物和进行导航的过程的优化算法。蜣螂是一种能够将粪球滚到合适地点的昆虫&#xff0c;它们利用天空中的光线和自身的感知能力来确…

关于深度学习中Attention的一些简单理解

Attention 机制 Attention应用在了很多最流行的模型中&#xff0c;Transformer、BERT、GPT等等。 Attention就是计算一个加权平均&#xff1b;通过加权平均的权值来自计算每个隐藏层之间的相关度&#xff1b; 示例 Attention 机制 Attention应用在了很多最流行的模型中&am…

挖掘业务场景的存储更优解

文章目录 第1章 如何用更优的数据存储方案&#xff0c;打造更稳定的架构&#xff1f;1.1 选用适合自己的数据存储方案1.1.1 关系型数据库1.1.2 非关系型数据库1.1.3 内存数据库 1.2 打造更稳定的架构1.2.1 分布式架构1.2.2 容灾备份1.2.3 监控报警1.2.4 自动化运维 1.3 案例分析…

redis中的io多线程(线程池)

文章目录 redis多线程模型redis为什么引入I/O多线程I/O多线程模型 源码解析测试设置连接建立数据传输线程调度开启io线程startThreadedIO关闭io线程stopThreadedIO redis多线程模型 redis为什么引入I/O多线程 Redis 的性能瓶颈在网络 IO 的处理上。Redis 是网络 IO 密集型&am…

Connectify Hotspot 23.0.1.40175 MAX Crack

您是学生吗&#xff1f;你在宿舍打游戏吗&#xff1f;你是在集体宿舍吗&#xff1f;如果是&#xff1a;你需要功能上网吧 Connectify Hotspot 专业 WiFi 热点共享管理工具 Connectify 是一款强大的无线热点工具&#xff0c;可以让带有无线网卡 / 3G 上网卡的电脑变成无线路由器…

百度网盘使用指南

文章目录 备份篇手机文件备份电脑文件备份 查找篇移动端PC端 文件操作文件解压文件扫描PDF工具图片工具音频操作 备份篇 手机文件备份 在百度网盘APP种点击 我的–设置–自动备份设置 里边有相册备份, 文档备份, 微信文件备份, 手机通讯录, 短信, 通话备份等功能 电脑文件备…