• Linux 进程线程


    一、进程线程基础概念

    1.程序:可执行文件,可执行指令的集合,是一个文件
    2.进程:动态的,运行在内存中,程序执行有一次的过程,伴随着资源的分配和释放;
    在这里插入图片描述
    3.程序的构成

    size a.out // size <程序名>
    test  //代码段
    rodate //只读数据段
    data  //数据段
    bss   //未初始化的段
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.进程的构成

    test  //代码段
    rodate //只读数据段
    data  //数据段
    bss   //未初始化的段
    堆、栈、系统相关的信息(命令行参数、环境变量)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.进程的表示
    task_struct 的结构体
    6.进程分类:
    (1)交互进程;//输入进程
    (2)批处理进程//windows 中.bat
    (3)守护进程//开机启动,系统关闭而关闭
    7.相关命令

    pstree //以树型查看当前进程的信息
    ps -ef //进程快照,查看当前进程
    ps -ef |grep "a.out"  //查找"a.out"相关进程
    
    ps -aux |grep "a.out" //查看当前进程号
    
    kill -l // 查看控制进程的信号
    //常用宏
    SIGKILL      9    杀死进程
    SIGCHLD     17    子进程结束时,给父进程发送信号
    SIGCONT   	18	让信号继续运行
    SIGSTOP	    19    让信号停止
    
    kill -9  11962
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    //示例:把一个进程放到后台运行 或者放到前台运行

    ./a.out   //默认前台运行
    ./a.out & //后台运行
    
    //前台运行一个进程
    ./a.out 
    //查看进程号
    ps -aux |grep a.out
    //停止进程
    kill -19  <pid>
    //jobs命令查看job号
    jobs
    
    //bg 
    bg 1 //把进程放到后台运行
    fg 1 //把进程放到前台运行
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    二、创建进程

    1.pid_t fork(void);//成功创建,返回0 ,失败返回-1;

    //fork()函数创建成功子进程,在子进程中,pid=0,在父进程中pid为子进程的进程号。
    (1)创建子进程,子进程把父进程堆区、栈区、可数据区、可读区、系统相关信息复制了一份,并且父子进程互不影响。
    (2)fork之后,子进程会继承父进程打开的文件描述符集合,共享文件状态标志位和问价偏移量。

    #include
    #include
    
    #include
    
    int main(int argc,const char * argv[])
    {
    	pid_t pid;
    	fork();//创建子进程;
    	printf("welcom to 22091\n");
    	while(1);
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    //示例:创建进程,显示子进程、父进程pid、父进程ppid
    //在父子进程输出printf()函数末尾必须加换行,或者flush(),刷新缓存,不然不能输出。

    #include
    #include
    
    int main(int argc,const char *argv[])
    {
    	pid_t pid;
    	pid=fork();
    	if(pid<0)
    	{
    		perror("Fail to fork");
    		return -1;
    	}
    	else if(pid==0)
    	{
    		printf("创建子进程成功,子进程pid:%d\n",getpid());
    		printf("父进程pid :%d\n",getppid());
    	}
    	else
    	{
    		printf("父进程pid:%d\n",getpid());
    		printf("父进程的父进程pid:%d\n",getppid());
    		
    	}
    	while(1);//创建阻塞
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    2.僵尸子进程:子进程结束的时候,父进程没有进行收尸操作(父进程还存在),此时占用资源;

    孤儿子进程:父进程结束了,子进程会编程孤儿子进程。

    
    
    • 1

    3.常用退出进程的函数

    (1)return 结束一个函数的执行,程序不一定结束;
    (2)void exit(int status)[库函数] ,需要添加 #include//结束一个进程,结束之前会刷新缓冲区;status :进程状态的标志,0表示正常结束,其他表示异常结束。

    #define EXIT_SUCCESS 0
    #define EXIT_FAILURE 1
    
    • 1
    • 2

    (3)void _exit(int status)[系统调用],需添加 #include 与exit不同是不刷新缓冲区;

    #include
    #include
    #include
    
    void func1()
    {
    	printf("func1");
    	
    }
    void func2()
    {
    	printf("func2");
    	exit(0);//刷新缓冲区,可以在终端输出内容
    	//_exit(0);//当使用该函数时,系统调用,没有缓冲区,故不能在终端输出内容;
    }
    int main(int argc, const char* argv[])
    {
    	func1();
    	func2();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4.回收僵尸态子进程

    pid_t wait();//返回值:成功返回僵尸子进程的pid,失败返回-1(没有子进程);当没有子进程时阻塞(可中断等待态s)

    //示例:创建僵尸子进程

    #include
    #include
    #include//exit()函数头文件
    int main(int argc, const char *argv[])
    {
    	pid_t pid;
    
    	pid=fork();//创建一个子进程
    	if(pid<0)
    	{
    		perror("Fail to fork");
    		return -1;
    	}
    	else if(pid==0)
    	{
    		sleep(3);
    		printf("child exit!\n");
    		exit(EXIT_SUCCESS);
    	}
    	else
    	{
    	
    	}
    
    	while(1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    // 子进程中断的原因
    ① exit()或_exit();//判断是exit()还是)_exit()使用宏函数 WIFEXITED(status),返回值为ture 则为exit(number),其中number =WEXITSTATUS(status);

    #include
    #include
    #include
    
    #include
    #include
    
    int main(int argc, const char *argv[])
    {
    	pid_t pid ,pid2;
    	int status;
    
    	pid=fork();//创建一个子进程
    	if(pid<0)
    	{
    		perror("Fail to fork");
    		return -1;
    	}
    	else if(pid==0)
    	{
    		sleep(3);
    		printf("child exit!\n");
    		exit(100);
    		//return 0;
    	}
    	else
    	{
    		pid2=wait(&status);	//父进程回收子进程,在子进程未结束时,父进程处于可中断等待态S
    		if(pid2<0)
    		{
    			perror("Fail to wait");
    			return -1;
    		}
    
    		if(WIFEXITED(status))//判断是exit() ,还是_exit(data)结束的子进程
    		{
    			printf("true is exit! exit(%d)\n",WEXITSTATUS(status));//子进程结束时的状态值为 data
    		}
    		printf("child exit pid =%d\n",pid2);//wait()返回值为子进程的pid号
    	
    	}
    
    	while(1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    ② return // return 和exit()一样
    ③信号 //信号结束子进程,WIFSIGNALED(status)判断是否是由信号结束的(status是从wait(&status)获得的),是由信号结束的子进程,用WTERMSIG(status) 的返回值知道结束子进程的信号;

    #include
    #include
    #include
    
    #include
    #include
    
    int main(int argc, const char *argv[])
    {
    	pid_t pid ,pid2;
    	int status;
    
    	pid=fork();//创建一个子进程
    	if(pid<0)
    	{
    		perror("Fail to fork");
    		return -1;
    	}
    	else if(pid==0)
    	{
    		sleep(100);
    		printf("child exit!\n");
    		exit(100);
    	}
    	else
    	{
    		pid2=wait(&status);	
    		if(pid2<0)
    		{
    			perror("Fail to wait");
    			return -1;
    		}
    
    		if(WIFEXITED(status))
    		{
    			printf("true is exit! exit(%d)\n",WEXITSTATUS(status));
    		}
    		printf("child exit pid =%d\n",pid2);
    
    		if(WIFSIGNALED(status))//判断子进程是否是由信号中断,返回值为ture 则是
    		{
    			printf("子进程由信号中断,中断号:%d\n",WTERMSIG(status));//获得中断子进程的信号
    		}
    	
    	}
    
    	while(1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    5.练习:打开一个文件,父进程(键盘输入)向文件写入一段字符串,子进程读出,在屏幕显示。

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    
    int main(int argc, const char *argv[])
    {
    	pid_t pid;
    
    	int fd;
    	ssize_t size1,size2;
    	
    	char buf[1024]={0};
    
    	if(argc!=2)
    	{
    		fprintf(stderr,"Usage: %s log.txt",argv[0]);
    		return -1;
    	}
    	fd=open(argv[1],O_RDWR  | O_CREAT | O_TRUNC,0666);
    	if(fd<0)
    	{
    		perror("Fail to fopen");
    		return -1;
    	}
    	pid =fork();
    	if(pid<0)
    	{
    		perror("Fail to fork()");
    		return -1;
    	}
    	else if(pid ==0)
    	{
    		int flag=0;
    		while(1)
    		{
    			usleep(300);
    			memset(buf,0,sizeof(buf));
    			ssize_t si=read(fd,buf,sizeof(buf));
    			if(si>0)
    			{
    				if(strncmp(buf,"quit",4)==0)
    				{
    					break;
    				}
    				printf("c:%s",buf);	
    			}			
    		}
    	}
    	else
    	{
    		char buf2[1024]={0};
    		while(1)
    		{
    			memset(buf,0,sizeof(buf));
    			fgets(buf,sizeof(buf),stdin);	
    			fflush(stdin);	
    			lseek(fd,0,SEEK_SET);
    			size2=write(fd,buf,sizeof(buf));//把buf中的字符写入fd
    			lseek(fd,0,SEEK_SET);
    			if(strncmp(buf,"quit",4)==0)
    			{
    				wait(NULL);
    				close(fd);
    				break;
    			}
    		}
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    6.pid_t waitpid(pid_t pid ,int *status,int options);//可设置非阻塞方式回收子进程

    //功能:回收子进程
    //返回值:
    //参数:
    //pid  -1  所有子进程,
    
    • 1
    • 2
    • 3
    • 4
    #include
    #include
    #include
    
    #include
    #include
    
    int main(int argc, const char *argv[])
    {
    	pid_t pid ,pid2;
    	int status;
    
    	pid=fork();//创建一个子进程
    	if(pid<0)
    	{
    		perror("Fail to fork");
    		return -1;
    	}
    	else if(pid==0)
    	{
    		sleep(100);
    		printf("child exit!\n");
    		exit(100);
    		//return 0;
    	}
    	else
    	{
    		while(1)
    		{
    			pid2=waitpid(-1,&status,WNOHANG);//0 以阻塞的方式调用	
    			if(pid2<0)
    			{
    				perror("Fail to wait");
    				return -1;
    			}
    			else if(pid2==0)
    			{
    				printf("pid2 =%d\n",pid2);
    				continue;
    			}
    			else
    			{
    				if(WIFEXITED(status))
    				{
    					printf("true is exit! exit(%d)\n",WEXITSTATUS(status));
    				}
    				printf("child exit pid =%d\n",pid2);
    
    				if(WIFSIGNALED(status))
    				{
    					printf("子进程由信号中断,中断号:%d\n",WTERMSIG(status));
    
    				}
    			}
    		}
    	
    	}
    	//while(1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    7.守护进程

    (1)前提:Linux 系统中,从终端运行的进程,当终端结束时,进程也结束。
    (2)查看守护进程

    ps -axj  //其中TPGID为-1的为守护进程
    
    • 1

    (3)创建守护进程
    //创建守护进程过程:
    ①创建子进程fork(),父进程退出"exit(EXIT_SUCCESS);
    ②在子进程中创建新的会话(脱离控制终端)setsid();
    ③改变进程的工作目录到|“/” :chdir(“/”);
    ④重设文件掩码 :umask(0);
    ⑤关掉不需要的文件描述符号:
    close(0);//标准输入
    close(1);//标准输出
    close(2);//标准出错
    //示例:守护进程每隔1秒在文件write_file 中打印:I am fine thank you!\n
    紧急关闭 :killall -9 a.out
    //多文件编程
    head.h

    #ifndef _HEAD_H_
    #define _HEAD_H_
    
    #include
    #include
    #include 
    #include 
    #include 
    #include
    extern void demon_func();
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    //demo.c

    #include
    #include
    #include
    #include
    #include
    
    
    void demon_func()
    {
    	pid_t pid;
    
    	pid=fork();
    	if(pid<0)
    	{
    		perror("Fail to fork");
    		return ;
    	}
    	else if(pid>0)
    	{
    		exit(EXIT_SUCCESS);
    	}
    	else
    	{
    		setsid();
    		chdir("/");
    		umask(0);
    
    		close(0);
    		close(1);
    		close(2);//关闭标准输入\输出\标准出错
    
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    //main.c

    //创建守护进程
    
    #include "head.h"
    
    int main(int argc, const char *argv[])
    {
    	int fd;
    	char buf[]={"I am fine, thank you!\n"};
    
    	fd=open("write_file",O_RDWR  | O_CREAT | O_TRUNC,0666);	
    	if(fd<0)
    	{		
    		perror("Fail to open");
    		return -1;
    	}
    		
    
    	demon_func();
    	while(1)
    	{
    		sleep(2);
    		write(fd,buf,strlen(buf));
    
    	}
    	close(fd);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Linux 进程线程目录及链接

    1.Linux 进程
    2.Linux 线程
    3.Linux进程间通信之无名管道通信
    4.Linux进程间通信之有名管道通信
    5.Linux 进程间通信—信号
    6.进程间通信之IPC对象

  • 相关阅读:
    JAVA毕业设计宠物寄存管理系统计算机源码+lw文档+系统+调试部署+数据库
    汇编语言循环左移和循环右移如何实现的,详细的比喻一下
    机器学习案例(九):语言检测
    华为笔试面试题
    java-php-python-宠物店管理计算机毕业设计
    Design A Dropbox
    Aptos、Solana和新公链周期律
    智云谷再获AR HUD新项目定点,打开HUD出口海外新通道
    Flutter 借助SearchDelegate实现搜索页面,实现搜索建议、搜索结果,解决IOS拼音问题
    二叉查找树迭代器
  • 原文地址:https://blog.csdn.net/jun8086/article/details/127727234