栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

操作系统 实验二 进程/线程基本编程练习

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

操作系统 实验二 进程/线程基本编程练习

【要求】所有练习题保留题目要求,在题目要求后面作答:

代码要求有注释,代码中适当标注关键代码为红色。

要有运行结果的截图。

每题最后应该有对程序的适当分析和总结!

注意格式排版,内容分析注意列条目,展开清楚地阐述。

1、分析理解多个进程的创建

1)若一个程序中有这样的代码,则有几个进程,父子关系如何?

#include
#include
#include
#include

int main(void){
         pid_t pid,pid2;
         char *message;
         int x;
         pid = fork();
pid2 = fork();
         if (pid < 0)
         {       perror("fork failed");
                  exit(1);     }

    补充完整后面的代码,使多个进程输出各自身份,并符合正确的亲缘关系

     if (  )
     {       message = "This is the childn";
             x = 0;       }
     ……
     printf("%s I'm %d, x=%d,my father is:%dn",message,x,getpid(),getppid());
     return 0;
}//main

给出代码及执行效果抓图,并要有说明分析!!!!谁先谁后,为什么。 

代码如下:

#include 
#include 
#include 
#include 

int main(void)
{
	pid_t pid,pid2;
	char *message;
	int x;
	pid = fork();
	pid2 = fork();
	if (pid < 0)
	{
		perror("fork failed");
		exit(1);
	}
	if(pid>0 && pid2>0)
	{//父进程
		message = "This is the fathern";
		x = 1;
	}else if(pid>0 && pid2==0)
	{//子进程2
		message = "This is the second childn";
		x = 2;
	}else if(pid==0 && pid2>0)
	{//子进程1
		message = "This is the first childn";
		x = 3;
	}else if(pid==0 && pid2==0)
	{//孙进程
		message = "This is the grandsonn";
        	x = 4;
    }
	printf("%s I'm %d, x=%d,my father is:%dn",message,x,getpid(),getppid());
	return 0;
}

执行效果如下:

当前父进程(7724)的父进程先运行(4258),在父进程(7724)的运行过程中产生了子进程,pid=0,pid2>0产生子进程1(7725);pid>0,pid2=0产生子进程2(7726),而pid=0,pid2=0使得子进程1(7725)又产生了新的子进程(7727);但由于父进程pid=0产生子进程1(7725)同时运行pid2,子进程2和孙进程(7727)顺序不能确定


2)若有如下的代码

for(i = 0; i <4; i++)
    {
        pid = fork();
……

请分析将产生多少个进程?要有说明分析!!!!

代码如下:

#include 
#include 
#include 
#include 

int main(void)
{
	pid_t pid;
	for(int i = 0; i < 4; i++)
	{
		pid = fork();
	}
	printf("%dn",getpid());
	return 0;
}

效果如下:

产生16个进程

调用一次fork()函数将得到两个返回值,而两个进程继续执行下一条fork(),则返回4个进程ID的值,依次可得到执行第i个fork函数后有2的i次方个进程


2、解释执行效果

若有下面的功能代码,执行会有怎样的输出?不只有抓图,要有说明分析!!!!谁先谁后,哪里停顿过。

int main(void){
         pid_t a;
         a = fork();
         if (a == 0) {
             sleep(2);
             execlp ("ps" ,"ps",NULL);      
    printf("%s I'm %d, x=%d,my father is:%dn",message,getpid(),getppid());
         }
         else 
    printf("%s I'm %d, x=%d,my father is:%dn",message,getpid(),getppid());

return 0;
}

代码如下:

执行如下图:

执行父进程(6393)时,语句直接执行;当a=0执行其子进程时先执行sleep休眠两秒,然后执行execlp运行ps展示当前进程,覆盖子进程的内容,因此不再执行printf语句。


3. 体验进程/线程的顺序控制。(基于对例5-9,5-11的理解,注意不是用sleep控制)

1)编写一个可产生父子进程的程序,使执行时子进程先printf输出内容,然后父进程再printf输出。

代码如下:

#include
#include
#include
#include
#include

int main(void)
{
    pid_t pc1, pw1;
    pc1 = fork();
    if(pc1 < 0){
        perror("fork failed");
        exit(1);
    }
    if(pc1 > 0){ //父进程
        pw1 = wait(NULL); //进入阻塞状态,等待其有亲缘的进程死亡后重新唤醒
        printf("Catch a dead child process with pid:%dn",pw1);
        printf("I'm %d, The father processn",getpid());
    }else{
        printf("I'm %d, The child process,my father process is %dn",getpid(),getppid());
    }
    return 0;
}

效果如下:

 pc1父进程运行时,当pw1 = wait(NULL)时,系统调用会使调用它的进程等待,进入阻塞状态,等待其有亲缘的子进程死亡进入僵死状态时,系统会重新把它从阻塞态唤醒,因此当父进程阻塞,子进程运行printf语句,运行完毕后子进程死亡,父进程被唤醒,执行printf语句

2)编写一个可产生两个线程(一个输出AAAAAA,一个输出BBBBBB)的程序,代码中要求控制线程的输出为AAAAAABBBBBB的顺序。然后修改控制代码,重新编译执行,得到另一种输出顺序,得到BBBBBBAAAAAA的输出。

代码如下:

#include 
#include 
#include 
#include 
#include 

char message[50] = "Hello World";
void *thread_function2(void *arg)
{
    printf("AAAAAA");
    pthread_exit("子线程结束");
}
void *thread_function1(void *arg)
{
    printf("BBBBBB");
    pthread_exit("子线程结束");
}
 
int main(void)
{
    int res1, res2;
    pthread_t thread1, thread2;
    void *thread_result1, *thread_result2;
    res1 = pthread_create(&thread1,NULL,thread_function1,(void*)message);
    res2 = pthread_create(&thread2,NULL,thread_function2,(void*)message);
    if(res1 != 0 || res2 != 0)
    {
        perror("Thread creation failed!");
        exit(EXIT_FAILURE);
    }
    res1 = pthread_join(thread1,&thread_result1);
    res2 = pthread_join(thread2,&thread_result2);
    if(res1 != 0 || res2 != 0)
    {
        perror("Thread join failed!n");
        exit(EXIT_FAILURE);
    }
    printf("n");
    exit(EXIT_FAILURE);
}

 编译执行 效果如下:

修改代码:修改代码只需调换void() 中thread_function1和2的顺序即可

重新编译执行效果如下:

由主进程产生一个线程,线程的功能为修改进程变量message字符串里的内容,利用join使主线程阻塞等待子线程结束返回后才继续执行,从而控制了两者的执行顺序。


4. 体验线程对共享变量的处理应互斥,否则会出现线程不安全问题。(选做)

两个线程对共享的进程变量做加1操作,结果加和是错的(例5-12),多次运行测试效果,体会程序执行原理,给出认识总结。

#include 
#include 
#include 
#include 
#include 

long x = 0, y = 0, z = 0;
void * thread_function1(void *arg)
{
    printf("===thread_function1 is running. n");
    while(1)
    {
        x++;
        z++;        }//while
    pthread_exit("===Thank you for your CPU time!");
}
void * thread_function2(void *arg)
{
    printf("===thread_function2 is running. n");
    while(1)
    {
        y++;
        z++;        }//while
    pthread_exit("===Thank you for your CPU time!");
}

int main(){
    int res;
    pthread_t thread1;
    pthread_t thread2;
    void *thread_result;
    res = pthread_create(&thread1,NULL,thread_function1,NULL);
    res = pthread_create(&thread2,NULL,thread_function2,NULL);
    
    sleep(1);

    printf("x = %dny = %dnx+y = %dnz = %dn",x,y,x+y,z);
    exit(EXIT_FAILURE);
}

代码功能很简单,主进程定义了三个变量x、y、z,主进程运行产生的两个线程共享这些变量 ,thread1和thread2分别持续对x和y做加1操作,但同时两者每次做加法,也对z做累加1的操作。主线程睡眠1秒后打印输出结果,然后进程结束。

执行效果如下:


多次运行测试:

两线程获得的CPU时间不确定,所以加法做的次数不同,x不等于y没什么问题;但在每次x加1、y加1时,它们也都使z加1了,正常逻辑下z的值和x+y的值应是相等的。

问题实际上出在双方对z的共同操作上。对z的加法操作在系统底层涉及从内存取到寄存器、再在寄存器累加、再保存回变量的内存的过程。两个线程都对z变量的内容做加法,由于线程并发执行,它们的加法操作相互穿插,难免出现其中一个的加法是在另一个加到一半的基础上做的,在错误的基础上做工作很容易出现错误的可能。

解决的办法是,需要提供控制手段,在多方对某种共享资源具有竞争关系时,保证只有一个使用者用完资源后另一个才能使用,这就是典型的资源互斥处理问题。

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

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

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