进程概念:一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源。
1.1 system函数启动新进程:
#include
int system (const char *string);
system函数启动一个新shell,然后由这个shell执行该命令。
1.2 替换进程映像exec函数系列:
#include
char **environ;
int execl(const char *path, const char *arg0, …, (char *) 0);
int execlp(const char *file, const char *arg0, …, (char *) 0);
int execle(cont char *path, const char *arg0, …, (char *) 0, char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const cha *path, char *const argv[], char *const envp[]);
一般情况下exec函数是不返回的,除非出现了错误。出现错误exec函数返回-1,并置errno指示相应错误。
由exec启动的新进程继承了原进程的许多特征,特别是在原进程中打开的文件描述符在新进程中依然保持打开,除非他们使用fcntl设置了close on exec flag。
1.3 复制进程映像fork函数:
#include
#include
pid_t fork(void);
fork创建一个新进程,这个系统调用复制当前进程,在进程表中创建一个新的表项,新表项中的许多属性与当前进程是相同的。fork和exec结合就可以创建新进程所需的一切了。
1.4 wait, waitpid函数和僵尸进程
wait函数:
#include
#include
pid_t wait(int *stat_loc)
wait系统调用将暂停父进程直到它的子进程结束为止。这个调用返回子进程的pid,它通常是已经结束运行的子进程的pid。如果stat_loc不是空指针,状态信息将被写入它所指的位置。状态信息允许父进程了解子进程的退出状态,即子进程的main函数返回的值或子进程中exit函数的退出码。
解释状态信息的宏:
Macro Definition
WIFEXITED(stat_val) Nonzero if the child is terminated normally.
WEXITSTATUS(stat_val) If WIFEXITED is nonzero, this returns child exit code.
WIFSIGNALED(stat_val) Nonzero if the child is terminated on an uncaught signal.
WTERMSIG(stat_val) If WIFSIGNALED is nonzero, this returns a signal number.
WIFSTOPPED(stat_val) Nonzero if the child has stopped.
WSTOPSIG(stat_val) If WIFSTOPPED is nonzero, this returns a signal number.
waitpid函数
#include
#include
pid_t waitpid( pid_t pid, int *stat_loc, int options)
wiatpid可以用来等待特定进程的结束,pid参数指定要等待的子进程的pid。如果它的值为-1, waitpid将返回任一子进程的信息。如果stat_loc是非空指针,waitpid将把状态信息写道它所指向的位置。Option参数允许我们改变waitpid的行为,WNOHANG选项是防止waitpid调用将调用者的执行挂起,如果想周期性的检查某个特定的子进程是否结束,可以如下调用:
waitpid(child_pid, (int *) 0, WNOHANG)
如果子进程没有结束或意外终止,它就返回0,否则返回child_pid。
僵尸进程
如果子进程不再运行,但它仍然存在于系统中,因为它的退出码还需要保存以备父进程今后的wait调用使用。这时它将成为一个死(defunct)进程或僵尸(zombie)进程。所以使用fork产生子进程一定要使用wait或waitpid函数,防止出现僵尸进程。
如果父进程异常终止,子进程将自动把pid为1的进程(init)作为自己的父进程。僵尸进程一直保留在进程表项直到init进程发现并释放。
2. 信号
2.1 发送信号给进程
在键盘上敲入中断字符(例如Ctrl+C组合键),可以向前台进程发送相应的信号。也可以使用kill命令发送命令,包括向后台进程。 Kill默认发送的是SIGTERM信号。其他信号可以使用如下发送, 如向pid为512的进程发送SIGHUP信号为:
Kill -HUP 512
发送信号函数:kill函数
#include
#include
int kill(pid_t pid, int sig);
alarm函数在经过预定的时间后发送一个SIGALARM信号
#include
Unsigned int alarm(unsigned int seconds);
2.2 信号处理函数
有两种设置信号处理函数的方法:signal和sigaction函数,推荐使用sigaction函数,它比较健壮。
signal库函数安装信号处理函数:
#include
void (*signal (int sig, void (*func)(int))) (int);
这个函数相当复杂,signal是一个带有sig和func两个参数的函数。准备捕获或忽略的信号由参数sig给出,接收到指定的信号后将要调用的函数由参数func给出。func还可以去两个特殊的值代替信号处理函数: SIG_IGN,表示忽略此信号;SIG_DFL,表示默认行为。
sigaction函数安装信号处理函数:
#include
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
struct sigaction的结构定义:
struct sigaction {
void (*sa_handler)(int); /* function, SIG_DFL or SIG_IGN
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask; /* signals to block in sa_handler
int sa_flags; /* signal action modifiers
void (*sa_restorer)(void);
}
如果oact不是空指针,sigaction将把原先对该信号的动作写到它指向的位置。如果oact为空指针,sigaction函数就不需要再做其他设置了。
act中的sa_handler是信号处理函数,还可以取SIG_IGN和SIG_DFL。
act中的sa_mask是信号屏蔽集,在sa_handerl调用的时候将被屏蔽的信号。
act中sa_flags的参数说明:
SA_NOCLDSTOP Don’t generate SIGCHLD when child processes stop.
SA_RESETHAND Reset signal action to SIG_DFL on receipt.
SA_RESTART Restart interruptible functions rather than error with EINTR.
SA_NODEFER Don’t add the signal to the signal mask when caught.
SA_RESTAT作用是在信号处理函数结束后重启中断的系统调用。许多系统调用都是可中断的。
SA_RESETHAND 是在信号处理函数处理后设置该信号处理函数为SIG_DFL
信号集有关的一些函数
#include
int sigaddset (sigset_t *set, int signo);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigdelset(sigset_t *set, int signo);
基本作用和函数名字相同。不多说了。
函数sigismember, 判断signo是不是在set信号集中
#include
int sigismember(sigset_t *set, int signo);
设置和检查进程的信号屏蔽字sigpromask函数
#include
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
how的取值和作用如下:
SIG_BLOCK The signals in set are added to the signal mask.
SIG_SETMASK The signal mask is set from set.
SIG_UNBLOCK The signals in set are removed from the signal mask.
如果参数set是空指针,how的值就没有意义,sigpromask的作用就是把当前信号屏蔽字的值保存到oset中。
sigpending函数
查看进程阻塞的信号中哪些正停留在待处理状态
#include
int sigpending(sigset *set);
sigsuspend函数