操作系统实验——进程与线程

目录

1.使用GCC

(1)参数

(2)自定义头文件

(3)makefile脚本

(4)gdb调试

2.进程

(1)新建进程:fork()

(2)执行:exec

(3)消亡:exit()

(4)阻塞:wait()

3.线程

(1)共同操作共享变量

(2)执行顺序控制


1.使用GCC

(1)参数

gcc test.c -o tested 

./tested

(2)自定义头文件

gcc testf.c -o test -I fdhead

-I:指定头文件所在目录,不指定参数将编译出错

#include <stdio.h>
#include "math.h"
void main()
{
    int x=2,y=4;
    printf("please input two numbers:\n");
    //scanf("%d,%d",&x,&y);
    printf("x*y=%d\n",Fmulitply(x,y));
    printf("x! is %f\n",Ffactorial(x));
    printf("y! is %f\n",Ffactorial(y));
}
int Fmulitply(int x, int y)
{
    int z;
    z=x*y;
    return z;		
}//Fmulitply

float Ffactorial(int t)
{
if (t==1)
      return 1;
else 
      return (float)t*Ffactorial(t-1);	
}//Ffactorial

(3)makefile脚本

vi makefile

test:test.c test.h (目标文件:依赖文件)

        gcc test.c –o test (达成目标使用的命令,句子前有一个tab

make

或 make test (目标名test与makefile中的要一致)

 myfile:

testf2 : testf.c math.h
	gcc testf.c -o testf2
cls : 
	rm testf2

除非特殊指定cls,否则只执行第一个,也就是testf2

(4)gdb调试

2.进程

(1)新建进程:fork()

fork():一次克隆,两个返回值

父进程返回子进程号,子进程返回0

例:如下图所示,应有几个进程?

4个:父,大儿子,二儿子,孙子

根据pid1和pid2的值可以判断出他们的身份

#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 child1\n";
		x = 10;	} 
	else if (pid > 0 && pid2 == 0)
	{	message = "This is the child2\n";//父亲第二次克隆孩子
		x = 20;		}
	else if (pid == 0 && pid2 == 0)
	{	message = "This is the child1-child\n";
		x = 30;		}
	else 
	{	message = "This is the parent\n";
		x = 0;	}
        printf("%s I'm %d, x=%d,my father is:%d\n",message,x,getpid(),getppid());
	return 0;
}//main

(2)执行:exec

exec是一个函数族,有很多函数,但最后都是下面这个函数执行。

例:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
	pid_t a;
	a = fork();
	if (a < 0)	{
		perror("fork failed");
		exit(1);	}
	if (a == 0) {
		printf("child come \n");
		execlp ("ps" ,"ps",NULL);	
		execlp ("ls" ,"ls","-al","/etc/passwd ",NULL);	
		printf("child exit\n");
		return 1;	} 	//if
	else 	{
		wait(NULL);
		printf("father exit\n");}//else
	return 0;				
}//main

 

execlp ("ps" ,"ps",NULL);    
execlp ("ls" ,"ls","-al","/etc/passwd ",NULL);    

执行第一行时代码就被新的覆盖了,所以不会再执行第二行。

只有exec调用失败返回-1,其后的代码才有可能得到执行。

(3)消亡:exit()

程序执行结束或调用exit后并不是马上消失,而是变为僵死状态

想要观察到孩子的僵死态,需要让父亲睡着,否则先祖会来给孩子收尸

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
	pid_t pid;
	char *message;
	int x; 
	pid = fork();
	if (pid < 0)
	{	perror("fork failed");
		exit(1);	}
	if (pid == 0) 
	{	message = "This is the child\n";
		x = 0; 	} 
	else 
	{	message = "This is the parent\n";
		x = 10;
		sleep(10);	}

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

 &使进程后台执行

22342就是僵尸进程

(4)阻塞:wait()

使调用它的进程等待,进入阻塞状态

子进程死亡会唤醒阻塞的父进程

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

int main(){
	pid_t pc1,pc2,pw1,pw2;
	pc1=fork();
	pc2=fork();

	if (pc1>0 && pc2>0) {     //*父进程
		pw1=wait(NULL);
		pw2=wait(NULL);
		printf("***Catch a dead child process with pid: %d\n",pw1);
		printf("***Catch a dead child process with pid: %d\n",pw2);
		printf("***I'M %d,THE MAIN PROCESS LEAVE!\n",getpid());		}//if
	if (pc1==0&&pc2>0) { 		//*大儿子
	     printf("===I'M the first child PID:%d,my father is:%d\n",getpid(),getppid());
	     sleep(10);	}	//if
	if (pc1>0&&pc2==0)  		//*二儿子
	    printf("===I'M the 2nd child PID:%d,my father is:%d,i don't sleep.\n",getpid(),getppid());
	if (pc1==0&&pc2==0)  		//*孙进程
	    printf("I'M grandson PID:%d,my father is:%d,no one is waiting for me.\n",getpid(),getppid());
	
	exit(0);		
}	//main

创建出4个进程后,父亲阻塞

大儿子输出以后,沉睡10s

二儿子输出然后死亡,唤醒父亲一次

孙子输出然后死亡,但是唤醒不了大儿子,因为大儿子是sleep而不是wait

直到10s后大儿子死亡,父亲才被真正唤醒,输出三句话。

3.线程

由于pthread库不是Linux系统默认的库,需要使用库libpthread.a,所以,编译连接时,命令后需加“-l pthread” 参数帮助编译器找到相应的库。

需要注意:线程可以创建新线程,两个线程是等同层次,不存在亲缘关系。

#include <othread.h>

创建线程函数:pthread_create

int pthread_create(pthread_t* tid,const pthread_attr_t* attr,void* (*start_rtn),void *restrict arg);

成功返回0,失败返回错误号

(1)tid:事先创建好的pthread_t类型的线程标识符,整型。成功时tid指向的内存单元被设置为新创建线程的线程ID。

(2)attr:设置线程属性,通常设为NULL。

(3)start_rtn:新创建的线程从此函数开始运行,无参数时设为NULL。

(4)arg:start_rtn函数的参数,无参数时设为NULL,有参数时输入参数的地址。当多于一个参数时使用结构体传入。
 

终止线程: pthread_cancel、pthread_exit

void pthread_exit(void *retval):retval表示线程退出状态,通常传NULL,终止自己。

int pthread_cancel(pthread_t tid):终止同进程中的另一个线程,tid是线程标识符。成功返回0,失败返回错误号

线程等待:pthread_join

pthread_join(tid,void * *retval):主线程等待子线程tid的终止,reval根据终止状态返回不同值。

return返回:reval为返回值

pthread_cancel终止:reval为PTHREAD_CANCEL常量

pthread_exit终止:pthread_exit的参数

对终止状态不感兴趣传NULL

(1)共同操作共享变量

例1:

①线程共享资源: 共同影响进程的message变量

②并发执行: 交替输出message当前的值

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
//#include <pthread>
//例5-10

char message[50] = "Hello World";	   
 //线程共享,初值为helloworld

void *thread_function(void *arg){
	int k=0;
    printf("===Thread_function1 is running. Argument was %s\n", (char *)arg);
//注意此处循环设置过少会使线程执行时间短,测试体现不出并发效果
	for(k=0;k<10;k++) {
		sleep(rand()%3);
		strcpy(message, "THREAD!");		}//for
	pthread_exit("===Thank you for your CPU time!");	}

void *thread_function2(void *arg){
	int k=0;
    printf("===Thread_function2 is running. Argument was %s\n", (char *)arg);
	for(k=0;k<10;k++) {
		sleep(rand()%3);
		strcpy(message,"ANOTHER THREAD!");	}//for
	pthread_exit("===Thank you for your CPU time!");	}

int main(){
	int res,k;
	pthread_t thread1;
	pthread_t thread2;
	void *thread_result;
	
	res = pthread_create(&thread1, NULL, thread_function, (void *)message);
	res = pthread_create(&thread2, NULL, thread_function2, (void *)message);

	for(k=0;k<20;k++) {   
	   sleep(1);
 	     printf("Message is now %s\n", message);
	}	//for

	exit(EXIT_FAILURE);
}

例2:两个线程对共享的进程变量做加1操作,结果加和是错的。

#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()
{
	printf("thread_function1 is running \n");
	while(1)
	{
		x++;
		z++;
	}	
	pthread_exit("thank you for your cpu time");
}

void *thread_function2()
{
	printf("thread_function2 is running \n");
	while(1)
	{
		y++;
		z++;
	}	
	pthread_exit("thank you for your cpu time");
}

int main(){
	int res;
	pthread_t thread1;
	pthread_t thread2;
	
	res=pthread_create(&thread1,NULL,thread_function1,NULL);//创建子线程
	res=pthread_create(&thread2,NULL,thread_function2,NULL);

	sleep(1);

	printf(" x= %d\n",x);
	printf(" y= %d\n",y);
	printf(" x+y = %d\n",x+y);
	printf(" z= %d\n",z);
	
	exit(EXIT_FAILURE);

}

按理说x+y=z,但是结果不对。

线程对共享变量的处理互斥,否则会出现线程不安全问题 

(2)执行顺序控制

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
//例5-11
char message[50] = "Hello World";
void *thread_function(void *arg) {
    printf("===CHILD run and want to sleep(5). message NOW is %s\n", (char *)arg);
    sleep(5);
    strcpy(message, "HELLO FATHER!");
    pthread_exit("===Thank you for your CPU time!");
}

int main(){
	int res;
	pthread_t threadCH;
	void *thread_result;
	res=pthread_create(&threadCH,NULL,thread_function,(void *)message);
	if(res!=0){
		perror("thread creation failed");
		exit(EXIT_FAILURE);	
	}
	printf("Main thread is waiting for thread to finish by join \n");

	res=pthread_join(threadCH,&thread_result);
	if(res!=0){
		perror("thread join failed\n");
		exit(EXIT_FAILURE);	
	}
	printf("child thread returned %s\n",(char *)thread_result);
	printf("message now is %s\n",message);

	exit(EXIT_FAILURE);

}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值