linux程序设计复习总结(八)进程和信号

1.进程:一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源。

2.Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份副本。

3.system函数在shell中运行以字符串参数的形式传递给它的命令并等待该命令的完成。

int system(const char *string);

4.exec函数可以把当前进程替换为一个新进程,新进程由path或file参数指定。你可以使用exec函数将程序的执行从一个程序切换到另一个程序。exec函数比system函数更有效,因为在新的程序启动后,原来的程序就不再运行了。新进程的PID、PPID和nice值与原先的完全一样。

5.在原进程中已打开的文件描述符在新进程中仍将保持打开,除非它们的“执行时关闭标志”(close on exec flag)被置位。任何在原进程中已打开的目录流都将在新进程中被关闭。

6.可以通过调用fork创建一个新进程。这个系统调用复制当前进程,在进程表中创建一个新的表项,新表项中的许多属性与当前进程是相同的。新进程几乎与原进程一模一样,执行的代码也完全相同,但新进程有自己的数据空间、环境和文件描述符。fork和exec函数结合在一起使用就是创建新进程所需要的一切了。

#include<sys/types.h>
#include<unistd.h>

pid_t fork(void);

因为fork出来的新进程和原进程代码相同,也就有两个fork(),根据返回值判定,父进程的返回值是子进程的pid,子进程的返回值是0.

7.有时,我们希望知道一个子进程何时结束,可以通过在父进程中调用wait函数让父进程等待子进程的结束。调用wait后父进程将自己的执行挂起,直到子进程的状态信息出现为止。

#include<sys/types.h>
#include<sys/wait.h>

pid_t wait(int *stat_loc);

返回值为子进程的pid,stat_loc中是子进程的退出状态,有一系列的宏定义。

8.子进程终止,父进程还未结束的时候,进程表中代表子进程的表项不会立即释放,子进程终止但是它扔存在于系统中,因为它的退出码还需要保存起来,以备父进程wait调用,这时候子进程成为僵尸进程。子进程终止,父进程还没调用wait或者异常结束,子进程将认init进程为父,僵尸进程将一直保留在进程表中直到被init进程发现并释放。进程表越大,这一过程就越慢。

9.waitpid函数

#include<sys/types.h>
#include<sys/wait.h>

pid_t waitpid(pid_t pid,int *stata_loc. int option);

pid参数指定需要等待的子进程的pid,如果pid为-1,将返回任一子进程的信息。option参数可用来改变waitpid的行为,其中一个有用的选项是WNOHANG,它的作用是防止waitpid将调用者的执行挂起。这样,父进程就可以周期性的来查看一下子进程是否终止。

如果子进程没有结束或意外终止,它就返回0,否则返回child_pid。如果waitpid失败,它将返回-1并设置errno。

10.已打开的文件描述符将在fork和exec调用之后保留下来,我们可以利用对进程这方面知识的理解来改变程序的行为。

11.信号是UNIX和Linux系统响应某些条件而产生的一个事件。接收到该信号的进程会相应地采取一些行动。我们用术语生成(raise)表示一个信号的产生,使用术语捕获(catch)表示接收到一个信号。信号可以被生成、捕获、响应或(至少对于一些信号)忽略。

12.程序可以用signal库函数来处理信号

#include<signal.h>

void (*signal(int sig, void (*func)(int))) (int);

signal有两个参数,sig是准备捕获的信号,func,接收到信号后的处理函数,处理函数必须带int参数接受信号,signal函数本身返回信号的处理函数,也可以用两个宏来代替func,SIG_IGN忽略信号,SIG_DFL恢复默认行为。

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
    printf("OUCH! - I got signal %d\n", sig);
    (void) signal(SIGINT, SIG_DFL);
}

int main()
{
    (void) signal(SIGINT, ouch);

    while(1) {
        printf("Hello World!\n");
        sleep(1);
    }
}

SIGINT为crtl-C发出的信号,启动程序,第一次按ctrl-C,转到ouch,打印那句话,同时将该信号的处理方式改为默认状态,第二次按ctrl-C,结束运行。

如果想保留信号处理函数,让它继续响应用户的Ctrl+C组合键,我们就需要再次调用signal函数来重新建立它。这会使信号在一段时间内无法得到处理,这段时间从调用中断函数开始,到信号处理函数的重建为止。如果在这段时间内程序接收到第二个信号,它就会违背我们的意愿终止程序的运行。不推荐大家使用signal接口,建议使用定义更清晰、执行更可靠的函数sigaction。

13.发送信号

进程可以通过调用kill函数向包括它本身在内的其他进程发送一个信号。如果程序没有发送该信号的权限,对kill函数的调用就将失败,失败的常见原因是目标进程由另一个用户所拥有。这个函数和同名的shell命令完成相同的功能。

只能发送信号给属于自己的进程,但超级用户可以发送信号给任何进程。

#include<sys/types.h>
#include<signal.h>

int kill(pid_t pid, int sig);

进程可以通过调用alarm函数在经过预定时间后发送一个SIGALRM信号。

#include<uinstd.h>
unsigned int alarm(unsigned int seconds);

把参数seconds设置为0将取消所有已设置的闹钟请求。如果在接收到SIGALRM信号之前再次调用alarm函数,则闹钟重新开始计时。每个进程只能有一个闹钟时间。

14.sigaction函数

#include<signal.h>

int sigaction(int sig, const struct sigaction *act,struct sigaction *oact);

sig:信号。

结构体act:

void (*) (int sa_handler):信号处理函数或SIG_IGN,SIG_DFL

sigset_t sa_mask:想要屏蔽的信号集

int sa_flag:一些特殊标志,勇于改变信号的行为,不需要就设0

oact:用来存放原来对该信号的处理,可为空

由sigaction函数设置的信号处理函数在默认情况下是不被重置的,如果希望获得类似前面用第二次signal调用对信号处理进行重置的效果,就必须在sa_flags成员中包含值SA_RESETHAND。

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
    printf("OUCH! - I got signal %d\n", sig);
}

int main()
{
    struct sigaction act;
	//指定处理函数
    act.sa_handler = ouch;
	//置空屏蔽信号集
    sigemptyset(&act.sa_mask);
	//不需要特殊标志
    act.sa_flags = 0;

    sigaction(SIGINT, &act, 0);

  while(1) {
    printf("Hello World!\n");
    sleep(1);
  }
}

15.信号集

头文件signal.h定义了类型sigset_t和一组用来处理信号集的函数。sigaction和其他函数将用这些信号集来修改进程在接收到信号时的行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值