欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Linux||Linux操作之Shell教程--使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区进程通信机制、消息队列实现进程通信(Ubuntu 16.04)

最编程 2024-07-04 07:19:27
...

实验1、使用fork创建进程

编写程序,使用系统调用fork()创建如下的进程树,当此程序运行时,在系统中有一个父进程和多个子进程活动,父进程等子进程运行结束后退出。

设置变量X=0,每一个进程在屏幕上显示不同的字符串,父进程的字符串内容要包括自己的学号、姓名、变量X的值;子进程字符串要包括进程PID、子进程序号(子进程1或2或3)、变量X的值,循环显示4次。每次循环X的值加2。记录屏幕上的显示结果,并分析变量X的变化规律

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_Linux

说明:getpid()获得进程的ID。

答:分析规律:可以看出两个子进程执行互不干预,结果具有不可再现性。

#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
int main()
{

    int i=0,X=0;
    pid_t p1,p2;
    p1 = fork();//鍒涘缓涓€涓柊process
    if(p1 < 0)
    {
            printf("fork() error");
            exit(1);
    }
    else if(p1 == 0)
    {
                for(int i = 0;i<4;i++)
                {
                        printf("The PID of child1 = %d, X = %d\n",getpid(),X);
                        X =X + 2;
                }
    }
    else
    {
        p2 = fork();//鍒涘缓绗簩涓柊杩涚▼
        if(p2 < 0)
        {
            printf("fork() error");
            exit(1);
        }
        else if(p2 == 0)
        {
                        for(int i = 0;i<4;i++)
                        {
                                printf("The PID of child2 = %d, X = %d\n",getpid(),X);
                                X = X + 2;
                        }
        }
        else
                {
                        for(int i = 0;i<4;i++)
                        {
                                printf("The PID of Parent = 2021308310230 鏉庡▍濠? X=%d\n",X);
                                X = X +2;
                        }
        }
    }
    getchar();//涓轰簡鎷︿綇杩涚▼锛屼笉璁╄繘绋嬬粨鏉?
    return 0;
}

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_Ubuntu_02

实验2、使用exec替换子进程程序

修改任务1编写的程序,将子进程改为独立的程序,父进程创建子进程并进行程序替换,观察程序执行时屏幕出现的现象,并分析原因。

答: printf("child process is running\n"); 未被打印,而是父进程回收到了子进程,正常退出。原因为:

1)进程间具有独立性,子进程的程序替换不会影响到父进程;

2)进程替换成功以后,就不会执行后续代码,即后续的printf语句不会执行;如果替换失败,就会继续执行后续代码。

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

int main()
{
	int i;
	int p, ppid;
	printf("begin\n");
	p = fork();
	if (p == -1)
	{
		printf("fork() error");
		exit(-1);
	}
	if (p == 0) //child process
	{ 
	    for (i=0; i<10; i++)
		{
			ppid=getppid();
			printf("This is child. The PID of Parent is %d\n", ppid);
			sleep(2);
		}
	}
	else
	{
		sleep(3);
		printf("This is parent. The parent process will stop running\n");
	}
	printf("The end\n");
	return 0;
}

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_子进程_03

实验3、分析进程的父进程。

在系统中,所有的进程组成一个进程树,但在实际操作中,存在中孤儿进程情况,孤儿进程就是父进程已终止,但是子进程没终止,然后就成孤儿。分析孤儿进程的父进程如何变化。

编写程序,要求如下:

父进程创建子进程;

子进程每2秒输出父进程的ID,循环10次;

父进程3秒后,输出自己的ID,结束进程;

分析程序的运行结果,重点说明子进程的父进程如何变化的。

答:从执行结果来看,此时由pid == 3729父进程创建的子进程,其输出的父进程pid == 1435,说明当其为孤儿进程时已被回收,最终并不会占用资源。

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h> 
#include <sys/msg.h> 
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#define KEY 100
#define SIZE 10
struct msgform{
	long mtype;
	char mtext[100];
}msg,smsg;
int main()
{
	int num[SIZE];
	int shmid,i;
	char *shmaddr;
	int sum=0;
	int *p;
	int x;
	int msgid;
	//use shm to deliver data
	shmid=shmget(KEY,sizeof(int)*SIZE,0777|IPC_CREAT);
	if(shmid==-1){
		printf("shmget error!\n");return 0;
	}
	shmaddr=shmat(shmid,NULL,0);
	p=(int *)shmaddr;
	//input data
	for(i=0;i<SIZE;i++){
		printf("杈撳叆绗?%d涓暟瀛?",i+1);
		scanf("%d",p++);
	}
	p=p-5;
	//compute sum of the five numbers
	for(i=0;i<SIZE;i++){
		sum+=*p++;
	}
	printf("SUM:%d\n",sum);
	//use msg queue to deliver result
	msgid=msgget(KEY+1,0777|IPC_CREAT);
	if(msgid==-1){
		printf("msgget error!");return 0;
	}
	if((x=fork())==-1){
		printf("fork error!\n");return 0;
	}
	if(x==0){// child process
		int sum_power2=0;
		p=p-5;
		for(i=0;i<SIZE;i++){
			int temp=*p++;
			sum_power2=sum_power2+temp*temp;
		}
		//send data
		smsg.mtype=1;
		sprintf(smsg.mtext,"%d",sum_power2);
		if(msgsnd(msgid,&smsg,100,0)==-1){
			printf("msgsnd error!\n");return 0;
		}
		return 0;
	}else{//parent process
		wait(NULL);
		//receive data
		msgrcv(msgid,&msg,100,1,0);
		printf("square sum:%s\n",msg.mtext);
	}
	//release resources
	msgctl(msgid,IPC_RMID,0);
	shmdt(shmaddr);shmctl(shmid,IPC_RMID,0);return 0;
}

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_子进程_04

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_子进程_05

实验4、共享存储区机制进程通信

编程实现生产者和消费者共享存储区功能。生产者随机产生10个整型数据,写入共享存储区;消费者读出数据,并进行平方和平方根运算后输出。使用系统调用shmget()、shmat()、sgmdt()、shmctl()等, 实现程序。

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_父进程_06

生产者:

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_共享存储_07

消费者:

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_共享存储_08

实验5、消息队列实现进程通信

修改上面的程序。父进程从键盘上接受10个数据,对其求和sum1,子进程求这10个数平方和sum2,使用消息队列方式将结果传给父进程,父进程计算sum1+sum2,打印结果。

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_Ubuntu_09

Linux||Linux操作之Shell教程-使用fork创建进程、使用exec替换子进程程序、分析进程的父进程、共享存储区机制进程通信、消息队列实现进程通信(Ubuntu 16.04)_Linux_10

实验心得与体会

通过本次实验了解和掌握了系统中进程创建和执行的方法,以及使用fork系统调用的用法;进程间具有独立性,子进程的程序替换不会影响到父进程;并且了解到了Linux系统中进程通信的基本原理。Linux系统的进程通信机构(IPC) 允许在任意进程间大批量地交换数据,熟悉了Linux支持的消息通讯机制和共享内存机制。

在共享存储器系统中,相互通信的进程共享某些数据结构或共享存储区,进程之间能够通过这些空间进行通信。据此,又可把它们分成以下两种类型:

(1)基于共享数据结构的通信方式。在这种通信方式中,要求诸进程公用某些数据结构,借以实现诸进程间的信息交换,如在生产者-消费者问题中的有界缓冲区。操作系统仅提供共享存储器,由程序员负责对公用数据结构的设置及对进程间同步的处理。这种通信方式仅适于传递相对少量的数据,通信效率低下,属于低级通信。

(2)基于共享存储区的通信方式。为了传输大量数据,在内存中划出了一块共享存储区域,诸进程可通过对该共享区的读或写交换信息,实现通信,数据的形式和位置甚至访问控制都是由进程负责,而不是OS。这种通信方式属于高级通信。需要通信的进程在通信前,先向系统申请获得共享存储区中的一个分区,并将其附加到自己的地址空间中,便可对其中的数据进行正常读、写,读写完成或不再需要时,将其归还给共享存储区。

实验指导

实验3参考代码

#include <sys/types.h>
#include <stdio.h>
int main()
{  int i;
     pid_t pid,ppid;
     printf("begin\n");
     pid = fork();
     if(pid == -1)
     {    printf("fork error");
          exit(-1);
     }
       if   (pid == 0) //child process
           { for (i=0; i<5; i++)
            {  ppid=getppid(); 
               printf("parent Pid:%d\n", ppid);
               sleep(2);
             }
            }
       else
       {   sleep(3);
           printf("The parent process will stop running\n");
        }
       printf("end");
     }