笔记仅归纳进程常用函数,具体函数用法看man手册
1、进程标识符pid
类型pid_t
查看进程命令 ps
#include <unistd.h>
pid_t getpid(void);
// 返回值:调用进程的进程ID
pid_t getppid(void);
// 返回值:调用进程的父进程ID
2、进程的产生
fork() --->一个现有的进程可以调用fork函数创建一个新进程
#include <unistd.h>
pid _t fork(void);
//返回值:子进程返回0,父进程返回子进程ID;若出错,返回-1
具体查看man手册: man fork
注意理解关键字:duplicating,意味着拷贝,克隆,一模一样等含义
fork 后父子进程的区别:fork 的返回值不一样,pid不同,ppid也不同,未决信号和文件锁不继承,资源利用量清0
init 进程:1号,是所有进程的祖先进程
调度器的调度策略来决定哪个进程先运行
fflush() 的重要性(在fork之前要先fflush(NULL)刷新一下流)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid;
printf("[%d]:Befin!\n",getpid()); //先打印一遍父进程
fflish(NULL); /*!!!在fork()之前刷新所有打开的流*/
pid = fork(); //创建子进程
if(pid < 0) //创建失败
{
perror("fork()");
exit(1);
}
if(pid == 0) //child,创建子进程成功,执行子进程的任务
{
printf("[%d]:Child is working!\n",getpid());
}
else //parent ,即pid > 0,否则执行父进程
{
printf("[%d]:Parent is working!\n",getpid());
}
printf("[%d]:End \n",getpid());
//getchar();
exit(0);
}
vfork();函数的调用序列和返回值fork相同,但两者的语义不同
用来创建一个新进程,而该新进程的目的是exec一个新程序
区别:
- vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit),于是也就不会引用该地址空间。不过在子进程调用exec或exit之前,它在父进程的空间中运行。
- vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行,当子进程调用这两个函数中的任意一个时,父进程会恢复运行。(如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。)
3、进程的消亡及释放资源
#include <sys/types.h>
#include <sys/wait.h>
wait();
waitpid();
//两个函数返回值:若成功,则返回进程ID;若出错,则返回0或-1
waitid();
wait3();
wait4();
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define LEFT 30000000
#define RIGHT 30000200
int main()
{
int i,j,mark;
pid_t pid;
for(i = LEFT; i <= RIGHT; i++) //parent
{
pid = fork();
if(pid < 0)
{
perror("fork()");
exit(1);
}
if(pid == 0) //child
{
mark = 1;
for(j = 2; j < i/2; j++)
{
if(i % j == 0)
{
mark = 0;
break;
}
}
if(mark)
{
printf("%d is a primer\n",i);
}
exit(0); /*一定要有退出,否则每一个子进程执行完会充当父进程继续创建子进程*/
}
}
for(i = LEFT; i < RIGHT; i++)
{
wait(NULL); //给子进程消亡并释放资源
}
exit(0);
}
4、exec 函数族
exec() -->当进程调用一种exec函数时,该进程执行的程序完全被替代为新程序,而新程序则从main函数开始执行
#include <unistd.h>
int execl (const char *pathname, const char *arg0, ..../* NULL */);
int execv (const char *pathname, char *const arg[ ]);
int execle (const char *pathname, const char *arg0, ..../* NULL, char *const envp[ ] */);
int execve(const char *pathname, char *const arg[ ], char *const envp[ ]);
//这四个函数取路径名作为参数
int execlp (const char *filename, const char *arg0, ..../* NULL */);
int execvp(const char *filename, char *const argv[ ]));
//这两个函数取文件名作为参数
- 如果filename中包含/, 则就将其视为路径名
- 否则就按PATH环境变量,在它所指定的各目录中搜寻可执行文件。其中PATH变量包含了一张目录表(称为路径前缀)目录之间用冒号:分隔。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
puts("Begin");
fflush(NULL); /*!!! exec()之前要用fflush(NULL)刷新一下流*/
//可以分别将结果在终端输出和重定向输出到文件,来看没有刷新流时的区别
execl("/bin/date","date","+%s",NULL);
perror("execl()");
exit(1);
puts("End");
exit(0);
}