(红色字体为分析)
【要求】所有练习题保留题目要求,在题目要求后面作答:
代码要求有注释,代码中适当标注关键代码为红色。
要有运行结果的截图。
每题最后应该有对程序的适当分析和总结!
注意格式排版,内容分析注意列条目,展开清楚地阐述。
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
给出代码及执行效果抓图,并要有说明分析!!!!谁先谁后,为什么。
2)若有如下的代码
for(i = 0; i < 5; i++)
{
pid = fork();
……
请分析将产生多少个进程?要有说明分析!!!!
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
pid_t pid;
char *message;
int x=0;
int i;
if (pid < 0)
{ perror("fork failed");
exit(1); }
if (pid>0){
sleep(5);
message="This is the father\n";
x=10;
}
else{
message="This is the child\n";
x=1;
}
printf("I'm %d, x=%d,my father is:%d\n",getpid(),x,getppid());
return 0;
}
由图可见主进程有五个子进程设分别为进程1,2,3,4,5
进程1有四个子进程分别为1.1 1.2 1.3 1.4
进程2有三个子进程分别为2.1 2.2 2.3
进程1.1同样有三个子进程分别为1.1.1 1.1.2 1.1.3
进程3有两个子进程分别为3.1 3.2
一共为32个进程。
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:%d\n",message,getpid(),getppid());
}
else
printf("%s I'm %d, x=%d,my father is:%d\n",message,getpid(),getppid());
return 0;
}
子进程睡了一会儿,所以父进程先输出,调用execlp函数ps中的内容覆盖子进程,输出ps的内容,子进程中原来的内容不再输出。
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 pid;
pid_t pw;
char *message;
int x;
pid=fork();
if(pid<0){
perror("fork failed");
exit(1);
}
if(pid>0){
pw=wait(NULL); //父进程等待子进程结束,子进程结束后父进程才继续执行
message="This is the father\n";
x=10;
}
else{
message="This is the child\n";
x=0;
}
printf("%s I'm %d, x=%d, my father is:%d\n",message,getpid(),getppid());
return 0;
}
- 编写一个可产生两个线程(一个输出AAAAAA,一个输出BBBBBB)的程序,代码中要求控制线程的输出为AAAAAABBBBBB的顺序。然后修改控制代码,重新编译执行,得到另一种输出顺序,得到BBBBBBAAAAAA的输出。
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
char message[50]="Hello World";
void * thread_function(void *arg)
{
printf("BBBBBB");
pthread_exit("child over");
}
void * thread_function2(void *arg)
{
printf("AAAAAA");
pthread_exit("child over");
}
int main(){
int res;
pthread_t thread,thread2;
void *thread_result;
res=pthread_create(&thread,NULL,thread_function,(void *)message);
res=pthread_create(&thread2,NULL,thread_function2,(void *)message);
if(res!=0){
perror("thread creation failed!\n");
exit(EXIT_FAILURE);
}
res=pthread_join(thread,&thread_result);
res=pthread_join(thread2,&thread_result);
}
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
char message[50]="Hello World";
void * thread_function(void *arg)
{
printf("BBBBBB");
pthread_exit("child over");
}
void * thread_function2(void *arg)
{
printf("AAAAAA");
pthread_exit("child over");
}
int main(){
int res;
pthread_t thread,thread2;
void *thread_result;
res=pthread_create(&thread,NULL,thread_function,(void *)message);
res=pthread_create(&thread2,NULL,thread_function2,(void *)message);
if(res!=0){
perror("thread creation failed!\n");
exit(EXIT_FAILURE);
}
res=pthread_join(thread2,&thread_result);
res=pthread_join(thread,&thread_result);
}
4. 体验线程对共享变量的处理应互斥,否则会出现线程不安全问题。
两个线程对共享的进程变量做加1操作,结果加和是错的(例5-12),多次运行测试效果,体会程序执行原理,给出认识总结。
错误解决方法:因为pthread并非Linux系统的默认库,而是POSIX线程库。连接时需要使用库libpthread.a,所以在使用pthread_create创建线程时,在编译中要加-lpthread参数。在Linux中将其作为一个库来使用,因此加上 -lpthread(或-pthread)以显式链接该库。
分析:thread1和thread2分别对x和y实现加1操作,正常逻辑下x+y的值应与z相等,但在进程进行的过程中可能会出现x或者y已经加1,但z还没有加1就被打断的情况,所以z还没写入就转入另一个进程,因而出现错误。可在两个进程上加入互斥,从而解决x+y不等于z的情况。