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 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 操作系统 实验二 进程/线程基本编程练习 -> 正文阅读

[C++知识库]操作系统 实验二 进程/线程基本编程练习

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

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

要有运行结果的截图。

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

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

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

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

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

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 child\n";
???????????? x = 0; ????? }

???? ……
?? ? printf("%s I'm %d, x=%d
my father is:%d\n",message,x,getpid(),getppid());
???? return 0;
}//main

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

代码如下:

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

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 father\n";
		x = 1;
	}else if(pid>0 && pid2==0)
	{//子进程2
		message = "This is the second child\n";
		x = 2;
	}else if(pid==0 && pid2>0)
	{//子进程1
		message = "This is the first child\n";
		x = 3;
	}else if(pid==0 && pid2==0)
	{//孙进程
		message = "This is the grandson\n";
        	x = 4;
    }
	printf("%s I'm %d, x=%d,my father is:%d\n",message,x,getpid(),getppid());
	return 0;
}

执行效果如下:

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


2)若有如下的代码

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

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

代码如下:

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

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

效果如下:

产生16个进程

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


2、解释执行效果

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

int main(void){
???????? pid_t a;

???????? a = fork();
???????? if (a == 0) {
???????????? sleep(2);
???????????? execlp ("ps" ,"ps",NULL);??????
??? printf("%s I'm %d, x=%dmy father is:%d\n",message,getpid(),getppid());
???????? }
???????? else?
??? printf("%s I'm %d, x=%dmy father is:%d\n",message,getpid(),getppid());

return 0;
}

代码如下:

执行如下图:

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


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

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

代码如下:

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


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:%d\n",pw1);
??????? printf("I'm %d, The father process\n",getpid());
??? }else{
??????? printf("I'm %d, The child process,my father process is %d\n",getpid(),getppid());
??? }
??? return 0;
}

效果如下:

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

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

代码如下:

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

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 <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

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 = %d\ny = %d\nx+y = %d\nz = %d\n",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变量的内容做加法,由于线程并发执行,它们的加法操作相互穿插,难免出现其中一个的加法是在另一个加到一半的基础上做的,在错误的基础上做工作很容易出现错误的可能。

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

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-27 17:12:03  更:2022-05-27 17:13:30 
 
开发: 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年5日历 -2024/5/13 18:17:44-

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