进程控制
fork函数
创建一个子进程。
pid_t fork(void);
失败返回-1;成功返回:
- 父进程返回子进程的ID(非负)
- 子进程返回 0
- pid_t类型表示进程ID,但为了表示-1,它是有符号整型。(0不是有效进程ID,init最小,为1)
注意返回值,不是fork函数能返回两个值,而是fork后,fork函数变为两个,父子需【各自】返回一个。
练习:通过命令行参数指定创建进程的个数,每个进程休眠1S打印自己是第几个被创建的进程。如:第1个子进程休眠0秒打印:“我是第1个子进程”;第2个进程休眠1秒打印:“我是第2个子进程”;第3个进程休眠2秒打印:“我是第3个子进程”。
//fork1.c
#include
#include
#include int main(void)
{
int i;
pid_t pid;
printf("xxxxxxxxxxx\n");
for (i = 0;
i < 5;
i++) {
pid = fork();
if (pid == 0) {
break;
}
}if (i < 5) {sleep(i);
printf("I'am %d child , pid = %u\n", i+1, getpid());
} else{
sleep(i);
printf("I'm parent\n");
}return 0;
}
getpid函数 获取当前进程ID
pid_t getpid(void);
getppid函数 获取当前进程的父进程ID
pid_t getppid(void);
区分一个函数是“系统函数”还是“库函数”依据:
- 是否访问内核数据结构
- 是否访问外部硬件资源
二者有任一 → 系统函数;二者均无 → 库函数
uid_t getuid(void);
获取当前进程有效用户ID
uid_t geteuid(void);
getgid函数(了解) 获取当前进程使用用户组ID
gid_t getgid(void);
获取当前进程有效用户组ID
gid_t getegid(void);
进程共享 父子进程之间在fork后。有哪些相同,那些相异之处。 刚fork之后: 父子相同处:
全局变量、.data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式...
父子不同处:
- 进程ID
- fork返回值
- 父进程ID
- 进程运行时间
- 闹钟(定时器)
- 未决信号集
当然不是!父子进程间遵循读时共享写时复制的原则。这样设计,无论子进程执行父进程的逻辑还是执行自己的逻辑都能节省内存开销。
实例:编写程序测试,父子进程是否共享全局变。
//fork_shared.c
#include
#include
#include int a = 100;
//.data int main(void)
{
pid_t pid;
pid = fork();
if(pid == 0){//son
a = 2000;
printf("child, a = %d\n", a);
} else {
sleep(1);
//保证son先运行
printf("parent, a = %d\n", a);
}return 0;
}
重点注意!躲避父子进程共享全局变量的知识误区!
【重点】:父子进程共享:
1. 文件描述符(打开文件的结构体)
2. mmap建立的映射区(进程间通信详解)
【进程控制】特别的,fork之后父进程先执行还是子进程先执行不确定。取决于内核所使用的调度算法。
推荐阅读
- 我的拖延症如何控制了我,又一次
- 多线程NSOperation
- 真正的爱
- 每天听本书《控制焦虑》
- 控制自己的心为什么这么难([追光日记(第2篇)])
- 《不要用爱控制我》
- 8、Flask构建弹幕微电影网站-搭建后台页面-密码修改、主页控制面板
- Android|Android Kotlin实现AIDL跨进程通信
- Promise|Promise 异步控制流
- 孕期血糖有点高怎么办(如何控制孕期血糖?看完觉得隐隐作痛)