=============================================================
系统编程技术点
1、进程的概念、接口函数
2、进程间的通信方式
3、进程间的信号集
4、线程的概念,函数接口,意义
5、线程之间的通信
6、线程池
进程的概念
进程:正在运行的程序
程序:hello.c ==> gcc hello.c -o hello (二进制程序)
进程:./hello (进程)
创建进程
在命令终端执行一个程序就产生一个进程: ./project
创建进程时,操作系统会产生一个结构体 : task_struct{}
产生一个任务管理结构体:结构体包含进程所需要的所有资源,包括当前进程状态,内存资源,进程ID等等。
linux中的进程
查看进程的相关命令:
ps -aux
ps -ef
top :动态显示当前系统中的所有进程
pstree : 树状图显示当前系统中的所有进程
例子:
systemd─┬─ManagementAgent───6*[{ManagementAgent}]
├─ModemManager─┬─{gdbus}
│ └─{gmain}
├─NetworkManager─┬─dhclient
│ ├─dnsmasq
│ ├─{gdbus}
注释:所有的进程有一个共同的源头 systemd (在Ubuntu14之前的版本,这个进程叫做init进程:祖进程 所有的进程都由这个进程、
产生。
进程的状态
就绪态、执行态、暂停态、睡眠态、僵尸态、死亡态
注释:进程是由另一个进程产生,产生这个进程的进程称为这个进程的父进程。
进程的相关函数
函数一:
pid_t fork(void);
函数功能:创建一个子进程
头文件:#include <unistd.h>
例:使用fork函数创建一个子进程,父进程中,每隔1秒,输出一个father,子进程中,每隔1秒,输出一个child
#include <stdio.h>
#include <unistd.h>
int main()
{
int i = 10;
pid_t pid;
printf("hello world\n");
//创建一个子进程
pid = fork();
//父进程执行部分
if(pid > 0){
i = 11;
while(1){
printf("In father code : i = %d\n", i);
sleep(1);
}
}
//子进程执行部分
if(pid == 0){
while(1){
printf("In child code : i = %d\n", i);
sleep(1);
}
}
if(pid < 0){
perror("fork failed");
}
return 0;
}
注意:
(1)fork创建子进程,父子进程相互独立,没有先后关系。
(2)父子进程的变量所占用的空间都是独立的
(3)父进程执行所有的代码,子进程执行fork下面的代码。
函数二:
pid_t getpid(void):查看自身进程的ID号
pid_t getppid(void):查看父进程的ID号
头文件:
#include <sys/types.h>
#include <unistd.h>
函数三:
1、pid_t wait(int *status):父进程阻塞等待回收子进程的资源
头文件:
#include <sys/types.h>
#include <sys/wait.h>
练习:获取子父进程的pid号
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
printf("pid = %d\n", pid);
if(pid > 0)
{
printf("father = %d\n", getpid());
sleep(1);
}
if(pid == 0)
{
printf("pid = %d, ppid =%d\n ", getpid(), getppid());
}
return 0;
}
2、pid_t waitpid(pid_t pid, int *status, int options);
参数:
status : int类型的指针,存放进程返回的状态
pid :
<-1 :父进程等待ID为pid的绝对值的进程
-1 :等待任意一个子进程 (相当于wait)
0 : 等待进程组中的任意一个进程
>0 : 等待指定的子进程
options :
WNOHANG :如果没有子进程退出,函数会立即返回(函数不会阻塞)
WUNTRACED :监听子进程状态,阻塞
WCONTINUED :阻塞监听子进程的恢复信号
返回值:成功 返回状态改变的子进程的pid
WNOHANG :没有进程状态改变,返回0, 失败 -1;
练习:
父进程创建2个子进程,父进程等待两个子进程结束,自己再结束。
子进程输出自己的进程号。进程号小的先结束。(越先创建的进程,进程号越小)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
int main()
{
pid_t pid1, pid2;
pid1 = fork();
if(pid1 < 0)
{
perror("fork failed");
return -1;
}
if(pid1 > 0)
{
pid2 = fork();
if(pid2 > 0)
{
sleep(5);//延时5秒后退出
}
if(pid2 < 0)
{
perror("fork 2 failed");
return -1;
}
if(pid2 == 0)
{
usleep(1000);
printf("child2 pid:%d\n", getpid());
usleep(1000);
}
}
if(pid1 == 0)
{
printf("child1 pid:%d\n", getpid());
}
return 0;
}
回收子进程资源
子进程结束,进入僵尸态。此时子进程拥有进程执行需要的资源(内存资源…)
此时需要父进程进行回收。如果父进程没有回收wait,并且父进程没有结束。子进程变成
僵尸进程: 资源未被回收,执行完毕的进程,父进程未结束。
回收方式:
(1)父进程调用wait/waitpid回收资源
(2)父进程结束,子进程由系统守护进程systemd统一回收
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
perror("fork failed");
return -1;
}
//创建子进程
if(pid > 0)
{
pid_t pid1;
pid1 = fork();
if(pid1 < 0)
{
perror("fork failed");
return -1;
}
//父进程
if(pid1 > 0)
{
//father
printf("In father\n");
wait(NULL);
wait(NULL);
}
//子进程2
if(pid1 == 0)
{
//child 2
int i;
for(i=0; i<5; i++)
{
printf("child 2 %d\n", getpid());
sleep(1);
}
}
}
//子进程1
if(pid == 0)
{
int i;
for(i=0; i<3; i++)
{
printf("child 1 %d helloworld\n", getpid());
sleep(1);
}
}
return 0;
}
进程退出函数
函数功能:结束进程
#include <unistd.h>
void _exit(int status); //直接结束进程,不清理输入输出缓冲区
#include <stdlib.h>
void exit(int status); //结束进程之前,清理输入输出缓冲区
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
printf("helloworld");
sleep(5);
//_exit(1); //直接结束进程
exit(1); //清理缓冲区之后,结束进程
while(1);
return 0;
}
进程结束的几种情况:
(1) 在main函数中执行 return
(2) 在任意一个函数中调用 exit()/_exit()
(3) 在主线程中调用 pthread_exit()
(4) 被信号 “杀死”
退出注册函数 (进程退出时执行的函数)
#include <stdlib.h>
int atexit(void (*function)(void));
参数:
参数为空,返回值为空的函数指针
返回值:成功
例:注册退出函数,在进程结束时使用。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void exit_fun(void)
{
printf("my pid : %d\n", getpid());
}
int main()
{
//注册退出执行函数
printf("main pid : %d\n", getpid());
int rt = atexit(exit_fun);
if(rt != 0)
{
printf("atexit failed");
return -1;
}
//exit(1); //执行退出执行函数
_exit(1); //不执行退出执行函数
printf("atexit success !\n");
return 0;
}
编程小tips:
printf(“hello world”);与printf(“hello world\n”) 的区别
printf(“hello world”):hello world会存放到缓冲区,不会立即输出到屏幕
printf(“hello world\n”):hello world不会存放到缓冲区,立即输出到屏幕
//无输出
#include <stdio.h>
int main(){
printf("hello world");
while(1);
}
//有输出
#include <stdio.h>
int main(){
printf("hello world\n");
while(1);
}