个人学习总结: 欢迎访问 http://aquariushome.duapp.com
1. 执行命令
#include <stdlib.h>
int system(const char *string);
等同于
$sh -c string
system 函数通过 shell 来启动进程,不建议使用
2. 替换进程映像
#include <unistd.h>
char **envron;
int execl(const char *paht, const char*arg0, ..., (char *)0);
int execlp(const char *file, const char *arg0, ..., (char *)0);
int execle(const 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 char *paht, char *const argv[], char *const envp[]);
以 p 结尾到函数会到 path 下搜索文件。
如果没后发生错误,该函数不会返回。
注意第一个参数位自己到名称,如:
execvp("ps", "ps", "ax", 0);
3. 复制进程映像
使用 fork
来复制进程映像,复制的子进程是完全独立的,如果父进程独立结束,那么子进程将会由 init 进程来接管。
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
fork 典型代码片段
pid_t new_pid;
new_pid = fork();
switch(new_pid){
case -1: /* Error */
break;
case 0: /* We are child */
break:
default: /* We are parent */
break;
}
4. 等待一个进程
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_loc);
wait 系统调用将暂停父进程直到他的子进程结束为止,这个调用返回子进程的 PID,他通常是已经结束运行的子进程 PID,使用一组宏来解释状态信息。
宏 | 说明 |
---|---|
WIFEXITED(stat_val) | 如果子进程正常结束,他就取一个非零值 |
WEXITSTATUS(stat_val) | 如果 WIFEXITED 非零,他返回子进程的退出码 |
WIFSIGNALED(stat_val) | 如果子进程是因为一个未铺货信号而终止,它就取一个非零值 |
WIFSTOPPED(stat_val) | 如果子进程意外终止,它就取一个非零值 |
WSTOPSIG(stat_val) | 如果 WIFSTOPPED 非零,它就返回一个信号代码 |
等待特定进程结束
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *stat_loc, int options);
参数 pid 为欲等待的子进程识别码, 其他数值意义如下:
pid | 意义 |
---|---|
pid<-1 | 等待进程组识别码为 pid 绝对值的任何子进程。 |
pid=-1 | 等待任何子进程,相当于 wait()。 |
pid=0 | 等待进程组识别码与目前进程相同的任何子进程。 |
pid>0 | 等待任何子进程识别码为 pid 的子进程。 |
5. 处理信号
#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);
signal 函数带有两个参数:
sig: 需要捕获的信号
func 信号处理函数
返回值:返回之前信号处理函数的指针
连个默认的信号处理函数宏
宏 | 意义 |
---|---|
SIG_IGN | 忽略信号 |
SIG_DEF | 恢复默认行为 |
例程:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch(int sig)
{
printf("OUCH! - put ssingnal %d\n", sig);
(void) signal(sig, SIG_DEF);
}
int main(int argc, char *argv[])
{
(void) signal(SIGINT, ouch);
while(1){
printf("Hello World\n");
sleep(1);
}
}
运行,第一次捕获中断打印消息并设置默认中断处理,第二次中断退出:
$./ctrlc1
Hello World
Hello World
^C
OUCH! - I got signal 2
Hello World
^C
$
注意:在信号处理函数中调用如 printf 这样的函数是不安全的。不推荐使用 signal
接口,而是使用 signation
接口。因为要考虑信号处理函数重入等情况。
6. 发送信号
给进程发送信号,如果用户没有权限,则调用失败。
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
在 seconds 秒后发送一个 SIGALRM 信号
#include <unistd.h>
unsigned int alarm(unsigned int secondes);
把程序搞起,知道收到一个信号为止:
#include <unistd.h>
int pause(void);
7. sigaction
#include <signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
sigaction 结构体:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
信号处理函数可以采用 void (sa_handler)(int)
或 void (*sa_sigaction)(int, siginfo_t , void )
。到底采用哪个要看 sa_flags 中是否设置了 SA_SIGINFO 位,如果设置了就采用void (*sa_sigaction)(int, siginfo_t , void *)
,此时可以向处理函数发送附加信息;默认情况下采用void (*sa_handler)(int)
,此时只能向处理函数发送信号的数值。
sa_handler
此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
sa_mask
用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置。
sa_restorer
此参数没有使用。
sa_flags
用来设置信号处理的其他相关操作,下列的数值可用。
sa_flags还可以设置其他标志:
SA_RESETHAND
:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
SA_RESTART
:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
SA_NODEFER
:一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号[1]
例程:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch(int sig)
{
printf("OUCH! - I got signal %d\n", sig);
}
int main(int argc, char *argv[])
{
struct sigaction act;
act.sa_handler = ouch;
sigemptyset(&act.sa_mask);
act.sa_flag = 0;
sigaction(SIGINT, &act, 0);
while(1){
printf("Hello World\n");
sleep(1);
}
}
信号集处理函数
#includ <signal.h>
int sigaddset(sigset_t *set, int signo);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigdelset(sigset_t *set, int signo);
int sigismember(sigset_t *set, int signo);
使用 sigprocmask
设置当前线程的屏蔽信号
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset *oset);
参数 how 来指定操作:
参数值 | 意义 |
---|---|
SIG_BLOCK | 把参数 set 中的信息添加到信号屏蔽字中 |
SIG_SETMASE | 把信号屏蔽字设置为参数 set 中的信号 |
SIG_UNBLOCK | 吧信号屏蔽字中删除参数 set 中的信号 |
一个信号如果被进程阻塞,它就不会传递给进程,但会停留在待处理状态,程序可以调用 sigpending
来查看他阻塞的信号中有哪些正在停留在待处理状态。
#include <signal.h>
int sigpending(sigset_t *set);
进程可以通过调用sigsuspend
函数来挂起自己的执行,直到信号集中的一个信号到达为止,这就是pause
函数的更通用的一种形式
#include <signal.h>
int sigsuspend(const sigset_t *sigmask);