Linux Programing -- ch11-- 进程和信号

个人学习总结: 欢迎访问 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

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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值