一 创建进程
1 进程号
进程号的类型是pid_t(typedef unsigned int pid_t)。
获得进程和父进程ID的API如下:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid();//获得进程ID
pid_t getppid();//获得父进程ID
2 进程复制
进程复制可以通过fork()函数以为进城为蓝本复制一个进程,其ID号和父进程不同,fork()执行一次返回两次。
父进程中返回子进程ID,子进程中返回0;创建进程失败返回-1。
#include <sys/types.h>
#include <unistd.h>
pid_t fork();
3 system()方式
system()函数调用shell的外部命令在当前进程中开始另一个进程。
调用成功会返回进程状态值,shell不能执行返回127,失败返回-1
#include <stdlib.h>
int system(const char *command);
4 进程执行exec()函数系列
exec()族函数会用更新进程代替原有的进程,新进程PID和原进程相同。
在当系统的可执行路径中根据指定的文件名找到合适的可执行文件名,并用来取代调用进程的内容,即在原来的进程内部运行一个可执行文件。
程序执行成功不返回,失败返回-1
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execle(const char *path, const char *arg, ... , char * const envp[]);
int execv(const char *path, char *const argv[]);
int execve(const char *filename, char *const argv[], char *const envp[]);
int execvp(const char *file, char * const argv[]);
int execlp(const char *file, const char *arg, ...);
其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
exec调用举例如下:
char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};
char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execv("/bin/ps", ps_argv);
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);
execve("/bin/ps", ps_argv, ps_envp);
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execvp("ps", ps_argv);
注意exec函数族形参展开时的前两个参数:
- 第一个参数是带路径的执行码(execlp、execvp函数第一个参数是无路径的,系统会根据PATH自动查找然后合成带路径的执行码)。
- 第二个是不带路径的执行码,执行码可以是二进制执行码和Shell脚本。
二 进程间通信
1 进程通过半双工管道通信
输入的数组是一个文件描述符的数组,用于保存管道返回的两个文件描述符(输入的时候直接定义数组,不需要赋初值)。
#include <unistd.h>
int pipe(int filedes[2]);
读写数据分别为read()和write()函数。关闭读写端口用close()函数。
int write(int *fd, char *str, int len);
//返回写入的字符数
//参数为:指向写端口的指针,写入的字符串指针,写入的字符串长度
int read(int *fd,