`
kenby
  • 浏览: 725392 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Linux信号详解

阅读更多

一 信号的种类

可靠信号与不可靠信号, 实时信号与非实时信号

可靠信号就是实时信号, 那些从UNIX系统继承过来的信号都是非可靠信号, 表现在信号

不支持排队,信号可能会丢失, 比如发送多次相同的信号, 进程只能收到一次. 信号值小于

SIGRTMIN的都是非可靠信号.

非可靠信号就是非实时信号, 后来, Linux改进了信号机制, 增加了32种新的信号, 这些信

号都是可靠信号, 表现在信号支持排队, 不会丢失, 发多少次, 就可以收到多少次. 信号值

位于 [SIGRTMIN, SIGRTMAX] 区间的都是可靠信号.

 

关于可靠信号, 还可以参考WIKI的一段话:

 

The real-time signals, ranging from SIGRTMIN to SIGRTMAX, are a set of signals that can be used for application-defined purposes.
Because SIGRTMIN may have different values on different Unix-like systems, applications should always refer to the signals in the form SIGRTMIN+n, where n is a constant integer expression.
The real-time signals have a number of properties that differentiate them from other signals and make them suitable for application-defined purposes:
* Multiple instances of a real-time signal can be sent to a process and all will be delivered.
* Real-time signals can be accompanied by an integer or pointer value (see sigqueue[2]).
* Real-time signals are guaranteed to be delivered in the order they were emitted.
 


命令行输入 kill -l, 可以列出系统支持的所有信号:

 

~> kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

非可靠信号一般都有确定的用途及含义,  可靠信号则可以让用户自定义使用

 

二 信号的安装

 

早期的Linux使用系统调用 signal 来安装信号


#include <signal.h>

void (*signal(int signum, void (*handler))(int)))(int); 

该函数有两个参数, signum指定要安装的信号, handler指定信号的处理函数.

该函数的返回值是一个函数指针, 指向上次安装的handler


经典安装方式:

if (signal(SIGINT, SIG_IGN) != SIG_IGN) {

    signal(SIGINT, sig_handler);

}

先获得上次的handler, 如果不是忽略信号, 就安装此信号的handler


由于信号被交付后, 系统自动的重置handler为默认动作, 为了使信号在handler

处理期间, 仍能对后继信号做出反应, 往往在handler的第一条语句再次调用 signal


sig_handler(ing signum)

{

    /* 重新安装信号 */

    signal(signum, sig_handler);

    ......

}

我们知道在程序的任意执行点上, 信号随时可能发生, 如果信号在sig_handler重新安装

信号之前产生, 这次信号就会执行默认动作, 而不是sig_handler. 这种问题是不可预料的.


使用库函数 sigaction  来安装信号

为了克服非可靠信号并同一SVR4和BSD之间的差异, 产生了 POSIX 信号安装方式, 使用

sigaction安装信号的动作后, 该动作就一直保持, 直到另一次调用 sigaction建立另一个

动作为止. 这就克服了古老的 signal 调用存在的问题


#include <signal.h> 
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));


经典安装方式:


struct sigaction action, old_action;



/* 设置SIGINT */

action.sa_handler = sig_handler;

sigemptyset(&action.sa_mask);

sigaddset(&action.sa_mask, SIGTERM);

action.sa_flags = 0;


/* 获取上次的handler, 如果不是忽略动作, 则安装信号 */

sigaction(SIGINT, NULL, &old_action);

if (old_action.sa_handler != SIG_IGN) {

    sigaction(SIGINT, &action, NULL);

}


基于 sigaction 实现的库函数: signal

sigaction 自然强大, 但安装信号很繁琐, 目前linux中的signal()是通过sigation()函数

实现的,因此,即使通过signal()安装的信号,在信号处理函数的结尾也不必

再调用一次信号安装函数。

 

三 如何屏蔽信号

 

所谓屏蔽, 并不是禁止递送信号, 而是暂时阻塞信号的递送, 

解除屏蔽后, 信号将被递送, 不会丢失. 相关API为


int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set, int signum);

int sigdelset(sigset_t *set, int signum);

int sigismember(const sigset_t *set, int signum);

int sigsuspend(const sigset_t *mask);

int sigpending(sigset_t *set);

-----------------------------------------------------------------

int  sigprocmask(int  how,  const  sigset_t *set, sigset_t *oldset));

sigprocmask()函数能够根据参数how来实现对信号集的操作,操作主要有三种:

* SIG_BLOCK 在进程当前阻塞信号集中添加set指向信号集中的信号

* SIG_UNBLOCK 如果进程阻塞信号集中包含set指向信号集中的信号,则解除

   对该信号的阻塞

* SIG_SETMASK 更新进程阻塞信号集为set指向的信号集


屏蔽整个进程的信号:

 

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>

void sig_handler(int signum)
{
    printf("catch SIGINT\n");
}

int main(int argc, char **argv)
{
    sigset_t block;
    struct sigaction action, old_action;

    /* 安装信号 */
    action.sa_handler = sig_handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;

    sigaction(SIGINT, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGINT, &action, NULL);
    }

    /* 屏蔽信号 */
    sigemptyset(&block);
    sigaddset(&block, SIGINT);

    printf("block SIGINT\n");
    sigprocmask(SIG_BLOCK, &block, NULL);

    printf("--> send SIGINT -->\n");
    kill(getpid(), SIGINT);
    printf("--> send SIGINT -->\n");
    kill(getpid(), SIGINT);
    sleep(1);

    /* 解除信号后, 之前触发的信号将被递送,
     * 但SIGINT是非可靠信号, 只会递送一次
     */
    printf("unblock SIGINT\n");
    sigprocmask(SIG_UNBLOCK, &block, NULL);

    sleep(2);

    return 0;
}

 运行结果:

 

work> ./a.out 
block SIGINT
--> send SIGINT -->
--> send SIGINT -->
unblock SIGINT
catch SIGINT

这里发送了两次SIGINT信号 可以看到, 屏蔽掉SIGINT后,

信号无法递送, 解除屏蔽后, 才递送信号, 但只被递送一次,

因为SIGINT是非可靠信号, 不支持排队.


只在信号处理期间, 屏蔽其它信号

在信号的handler执行期间, 系统将自动屏蔽此信号, 但如果

还想屏蔽其它信号怎么办?  可以利用 struct sigaction 结构体

的 sa_mask 属性.

 

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>

void sig_handler(int signum)
{
    printf("in handle, SIGTERM is blocked\n");
    /* 在此handler内将屏蔽掉SIGTERM, 直到此handler返回 */
    printf("--> send SIGTERM -->\n");
    kill(getpid(), SIGTERM);
    sleep(5);
    printf("handle done\n");
}

void handle_term(int signum)
{
    printf("catch sigterm and exit..\n");
    exit(0);
}

int main(int argc, char **argv)
{
    struct sigaction action, old_action;

    /* 设置SIGINT */
    action.sa_handler = sig_handler;
    sigemptyset(&action.sa_mask);
    /* 安装handler的时候, 设置在handler
     * 执行期间, 屏蔽掉SIGTERM信号 */
    sigaddset(&action.sa_mask, SIGTERM);
    action.sa_flags = 0;

    sigaction(SIGINT, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGINT, &action, NULL);
    }

    /* 设置SIGTERM */
    action.sa_handler = handle_term;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;

    sigaction(SIGTERM, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGTERM, &action, NULL);
    }

    printf("--> send SIGINT -->\n");
    kill(getpid(), SIGINT);

    while (1) {
        sleep(1);
    }

    return 0;
}

 

运行结果:

 

work> ./a.out
--> send SIGINT -->
in handle, SIGTERM is blocked
--> send SIGTERM -->
handle done
catch sigterm and exit..

 收到SIGINT后, 进入sig_handler,此时发送SIGTERM信号将被屏蔽,

 等sig_handler返回后, 才收到SIGTERM信号, 然后退出程序

 

 

四 如何获取未决信号

所谓未决信号, 是指被阻塞的信号, 等待被递送的信号. 


int sigsuspend(const sigset_t *mask));

sigpending(sigset_t *set))获得当前已递送到进程,

却被阻塞的所有信号,在set指向的信号集中返回结果。

 

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>

/* 版本1, 可靠信号将被递送多次 */
//#define MYSIGNAL SIGRTMIN+5
/* 版本2, 不可靠信号只被递送一次 */
#define MYSIGNAL SIGTERM

void sig_handler(int signum)
{
    psignal(signum, "catch a signal");
}

int main(int argc, char **argv)
{
    sigset_t block, pending;
    int sig, flag;

    /* 设置信号的handler */
    signal(MYSIGNAL, sig_handler);

    /* 屏蔽此信号 */
    sigemptyset(&block);
    sigaddset(&block, MYSIGNAL);
    printf("block signal\n");
    sigprocmask(SIG_BLOCK, &block, NULL);

    /* 发两次信号, 看信号将会被触发多少次 */
    printf("---> send a signal --->\n");
    kill(getpid(), MYSIGNAL);
    printf("---> send a signal --->\n");
    kill(getpid(), MYSIGNAL);

    /* 检查当前的未决信号 */
    flag = 0;
    sigpending(&pending);
    for (sig = 1; sig < NSIG; sig++) {
        if (sigismember(&pending, sig)) {
            flag = 1;
            psignal(sig, "this signal is pending");
        } 
    }
    if (flag == 0) {
        printf("no pending signal\n");
    }

    /* 解除此信号的屏蔽, 未决信号将被递送 */
    printf("unblock signal\n");
    sigprocmask(SIG_UNBLOCK, &block, NULL);

    /* 再次检查未决信号 */
    flag = 0;
    sigpending(&pending);
    for (sig = 1; sig < NSIG; sig++) {
        if (sigismember(&pending, sig)) {
            flag = 1;
            psignal(sig, "a pending signal");
        } 
    }
    if (flag == 0) {
        printf("no pending signal\n");
    }

    return 0;
}

  这个程序有两个版本:

可靠信号版本, 运行结果:

work> ./a.out 
block signal
---> send a signal --->
---> send a signal --->
this signal is pending: Unknown signal 39
unblock signal
catch a signal: Unknown signal 39
catch a signal: Unknown signal 39
no pending signal

发送两次可靠信号, 最终收到两次信号


非可靠信号版本, 运行结果:

 

work> ./a.out 
block signal
---> send a signal --->
---> send a signal --->
this signal is pending: Terminated
unblock signal
catch a signal: Terminated
no pending signal

  发送两次非可靠信号, 最终只收到一次

 

五 被中断了的系统调用

一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,

系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统

遇到了一个问题: 是重新开始这个系统调用, 还是让系统调用失败?


早期UNIX系统的做法是, 中断系统调用, 并让系统调用失败, 比如read

返回 -1, 同时设置 errno 为 EINTR


中断了的系统调用是没有完成的调用, 它的失败是临时性的, 如果再次调用

则可能成功, 这并不是真正的失败, 所以要对这种情况进行处理, 典型的方式为:


while (1) {

    n = read(fd, buf, BUFSIZ);

    if (n == -1 && errno != EINTR) {

        printf("read error\n");

        break;

    }

    if (n == 0) {

        printf("read done\n");

        break;

    }

}


这样做逻辑比较繁琐, 事实上, 我们可以从信号的角度

来解决这个问题,  安装信号的时候, 设置 SA_RESTART

属性, 那么当信号处理函数返回后, 被该信号中断的系统

调用将自动恢复. 

 

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>

void sig_handler(int signum)
{
    printf("in handler\n");
    sleep(1);
    printf("handler return\n");
}

int main(int argc, char **argv)
{
    char buf[100];
    int ret;
    struct sigaction action, old_action;

    action.sa_handler = sig_handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    /* 版本1:不设置SA_RESTART属性
     * 版本2:设置SA_RESTART属性 */
    //action.sa_flags |= SA_RESTART;

    sigaction(SIGINT, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGINT, &action, NULL);
    }

    bzero(buf, 100);

    ret = read(0, buf, 100);
    if (ret == -1) {
        perror("read");
    }

    printf("read %d bytes:\n", ret);
    printf("%s\n", buf);

    return 0;
}

 

版本1, 不设置 SA_RESTART 属性 :

 

work> gcc signal.c 
work> ./a.out 
^Cin handler
handler return
read: Interrupted system call
read -1 bytes:

在 read 等待数据期间, 按下ctrl + c, 触发 SIGINT 信号, 

handler 返回后, read 被中断, 返回 -1


版本2, 设置 SA_RESTART 属性:

 

work> gcc signal.c 
work> ./a.out 
^Cin handler
handler return
hello, world
read 13 bytes:
hello, world

 handler 返回后, read 系统调用被恢复执行, 继续等待数据.

 

 

六 非局部控制转移


int setjmp(jmp_buf env);

int sigsetjmp(sigjmp_buf env, int savesigs);

void longjmp(jmp_buf env, int val);

void siglongjmp(sigjmp_buf env, int val);

--------------------------------------------------------

setjmp()会保存目前堆栈环境,然后将目前的地址作一个记号,

而在程序其他地方调用 longjmp 时便会直接跳到这个记号位置,

然后还原堆栈,继续程序好执行。 


setjmp调用有点fork的味道, setjmp()return 0 if returning directly, 

and non-zero when returning from longjmp using  the saved context.


if (setjmp(jmpbuf)) {

   printf("return from jmp\n");

} else {

   printf("return directly\n");

}


setjmp 和 sigsetjmp 的唯一区别是: setjmp 不一定会恢复信号集合,

而sigsetjmp可以保证恢复信号集合

 

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <setjmp.h>

void sig_alrm(int signum);
void sig_usr1(int signum);
void print_mask(const char *str);

static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjmp;
static int sigalrm_appear;

int main(int argc, char **argv)
{
    struct sigaction action, old_action;

    /* 设置SIGUSR1 */
    action.sa_handler = sig_usr1;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;

    sigaction(SIGUSR1, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGUSR1, &action, NULL);
    }

    /* 设置SIGALRM */
    action.sa_handler = sig_alrm;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;

    sigaction(SIGALRM, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGALRM, &action, NULL);
    }

    print_mask("starting main:");

    if (sigsetjmp(jmpbuf, 1) != 0) {
        print_mask("exiting main:");
    } else {
        printf("sigsetjmp return directly\n");
        canjmp = 1;
        while (1) {
            sleep(1);
        }
    }

    return 0;
}

void sig_usr1(int signum)
{
    time_t starttime;
    if (canjmp == 0) {
        printf("please set jmp first\n");
        return;
    }

    print_mask("in sig_usr1:");

    alarm(1);
    while (!sigalrm_appear);
    canjmp = 0;
    siglongjmp(jmpbuf, 1);
}

void sig_alrm(int signum)
{
    print_mask("in sig_alrm:");
    sigalrm_appear = 1;

    return;
}

void print_mask(const char *str) 
{
    sigset_t sigset;
    int i, errno_save, flag = 0;

    errno_save = errno;

    if (sigprocmask(0, NULL, &sigset) < 0) {
        printf("sigprocmask error\n");
        exit(0);
    }

    printf("%s\n", str);
    fflush(stdout);

    for (i = 1; i < NSIG; i++) {
        if (sigismember(&sigset, i)) {
            flag = 1;
            psignal(i, "a blocked signal");
        }
    }

    if (!flag) {
        printf("no blocked signal\n");
    }

    printf("\n");
    errno = errno_save;
}
 

运行结果: 

 

work> ./a.out &
[4] 28483
starting main:
no blocked signal

sigsetjmp return directly

kill -USR1 28483

in sig_usr1:
a blocked signal: User defined signal 1

in sig_alrm:
a blocked signal: User defined signal 1
a blocked signal: Alarm clock

exiting main:
no blocked signal
 

 

七 信号的生命周期

 

从信号发送到信号处理函数的执行完毕

对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,

可以分为三个重要的阶段,这三个阶段由四个重要事件来刻画:

信号诞生;信号在进程中注册完毕;信号在进程中的注销完毕;信号处理函数执行完毕。


下面阐述四个事件的实际意义:

信号"诞生"。信号的诞生指的是触发信号的事件发生

(如检测到硬件异常、定时器超时以及调用信号发送函数

kill()或sigqueue()等)。信号在目标进程中"注册";

进程的task_struct结构中有关于本进程中未决信号的数据成员:

struct sigpending pending:

struct sigpending{

struct sigqueue *head, **tail;

sigset_t signal;

};


第三个成员是进程中所有未决信号集,第一、第二个成员分别指向一个

sigqueue类型的结构链(称之为"未决信号链表")的首尾,链表中

的每个sigqueue结构刻画一个特定信号所携带的信息,并指向下一个

sigqueue结构:

struct sigqueue{

struct sigqueue *next;

siginfo_t info;

}


信号的注册

信号在进程中注册指的就是信号值加入到进程的未决信号集中

(sigpending结构的第二个成员sigset_t signal),

并且加入未决信号链表的末尾。 只要信号在进程的未决信号集中,

表明进程已经知道这些信号的存在,但还没来得及处理,或者该信号被进程阻塞。

当一个实时信号发送给一个进程时,不管该信号是否已经在进程中注册,

都会被再注册一次,因此,信号不会丢失,因此,实时信号又叫做"可靠信号"。

这意味着同一个实时信号可以在同一个进程的未决信号链表中添加多次. 

当一个非实时信号发送给一个进程时,如果该信号已经在进程中注册,

则该信号将被丢弃,造成信号丢失。因此,非实时信号又叫做"不可靠信号"。

这意味着同一个非实时信号在进程的未决信号链表中,至多占有一个sigqueue结构.

一个非实时信号诞生后,

(1)、如果发现相同的信号已经在目标结构中注册,则不再注册,对于进程来说,

相当于不知道本次信号发生,信号丢失.

(2)、如果进程的未决信号中没有相同信号,则在进程中注册自己。


信号的注销。

在进程执行过程中,会检测是否有信号等待处理

(每次从系统空间返回到用户空间时都做这样的检查)。如果存在未决

信号等待处理且该信号没有被进程阻塞,则在运行相应的信号处理函数前,

进程会把信号在未决信号链中占有的结构卸掉。是否将信号从进程未决信号集

中删除对于实时与非实时信号是不同的。对于非实时信号来说,由于在未决信

号信息链中最多只占用一个sigqueue结构,因此该结构被释放后,应该把信

号在进程未决信号集中删除(信号注销完毕);而对于实时信号来说,可能在

未决信号信息链中占用多个sigqueue结构,因此应该针对占用sigqueue结构

的数目区别对待:如果只占用一个sigqueue结构(进程只收到该信号一次),

则应该把信号在进程的未决信号集中删除(信号注销完毕)。否则,不应该在进程

的未决信号集中删除该信号(信号注销完毕)。 

进程在执行信号相应处理函数之前,首先要把信号在进程中注销。


信号生命终止。

进程注销信号后,立即执行相应的信号处理函数,执行完毕后,

信号的本次发送对进程的影响彻底结束。

 

八 关于可重入函数

 

在信号处理函数中应使用可重入函数。

信号处理程序中应当使用可重入函数

(注:所谓可重入函数是指一个可以被多个任务调用的过程,

任务在调用时不必担心数据是否会出错)。因为进程在收到信号

后,就将跳转到信号处理函数去接着执行。如果信号处理函数中

使用了不可重入函数,那么信号处理函数可能会修改原来进程中

不应该被修改的数据,这样进程从信号处理函数中返回接着执行时,

可能会出现不可预料的后果。不可再入函数在信号处理函数中被视为

不安全函数。满足下列条件的函数多数是不可再入的:

(1)使用静态的数据结构,如getlogin(),gmtime(),getgrgid(),

    getgrnam(),getpwuid()以及getpwnam()等等;

(2)函数实现时,调用了malloc()或者free()函数;

(3)实现时使用了标准I/O函数的。The Open Group视下列函数为可再入的:

    _exit()、access()、alarm()、cfgetispeed()、cfgetospeed()、

    cfsetispeed()、cfsetospeed()、chdir()、chmod()、chown() 、

    close()、creat()、dup()、dup2()、execle()、execve()、

    fcntl()、fork()、fpathconf()、fstat()、fsync()、getegid()、

    geteuid()、getgid()、getgroups()、getpgrp()、getpid()、

    getppid()、getuid()、kill()、link()、lseek()、mkdir()、

    mkfifo()、 open()、pathconf()、pause()、pipe()、raise()、

    read()、rename()、rmdir()、setgid()、setpgid()、setsid()、

    setuid()、 sigaction()、sigaddset()、sigdelset()、sigemptyset()、

    sigfillset()、sigismember()、signal()、sigpending()、     

    sigprocmask()、sigsuspend()、sleep()、stat()、sysconf()、      

    tcdrain()、tcflow()、tcflush()、tcgetattr()、tcgetpgrp()、

    tcsendbreak()、tcsetattr()、tcsetpgrp()、time()、times()、

    umask()、uname()、unlink()、utime()、wait()、waitpid()、

    write()。


即使信号处理函数使用的都是"安全函数",同样要注意进入处理函数时,

首先要保存errno的值,结束时,再恢复原值。因为,信号处理过程中,

errno值随时可能被改变。另外,longjmp()以及siglongjmp()没有被列为可重入函数,

因为不能保证紧接着两个函数的其它调用是安全的。

分享到:
评论
1 楼 bzhao 2015-08-29  
好,赞扬!

相关推荐

    unix/linux信号详解大全

    Unix/Linux 信号详解大全 Unix/Linux 操作系统中,信号是一种异步事件处理机制,用于通知进程某个事件的发生。信号可以由硬件异常、软件异常、终止进程、进程挂起、定时器到期等事件触发。本文将对 Unix/Linux 信号...

    linux 信号详解

    Linux 信号是操作系统用于进程间通信和异常处理的重要机制,它是软件中断的一种形式。信号提供了一种处理异步事件的方式,比如终端用户按键中断、硬件异常或者软件条件触发。信号的处理方式包括忽略、捕捉(自定义...

    linux信号量详解

    ### Linux信号量详解 #### 一、信号量概念与历史 1965年,E.W.Dijkstra引入了信号量的概念,这是一种操作系统中用于实现进程间互斥和同步的重要机制。信号量本质上是一个包含了非负整型变量的数据结构,伴随着两个...

    linux信号量说明

    ### Linux信号详解 #### 一、引言 在Linux系统中,信号是一种进程间通信机制,主要用于异步通知进程发生了某种事件。通过本篇文章,我们将详细介绍Linux中的信号及其作用。 #### 二、信号概述 Linux信号是操作...

    Linux信号使用.pdf

    ### Linux信号详解 #### 一、引言 在Linux系统中,信号是一种进程间通信机制,主要用于异步通知进程发生了某种事件。通过本篇文章,我们将深入探讨Linux信号的基础概念、不同信号的功能及其应用场景。 #### 二、...

    Linux下信号介绍与函数

    `Linux信号详解1.doc`和`linux信号详解2.doc`可能进一步阐述了信号的发送、接收、处理和屏蔽等操作。例如,`raise()`函数可以由进程主动发送信号给自己,而`signal()`函数则用于设定信号处理器。 `signal.doc`文件...

    Linux信号列表详解.docx

    Linux信号列表详解 Linux信号列表详解是Linux系统中的一种机制,用于处理异步事件,以便程序可以响应外部事件,如键盘输入、终端断开、子进程结束等。信号机制是Linux系统中的一种基本机制,广泛应用于各种应用程序...

    [Linux命令详解词典]

    《Linux命令详解词典》是由施威铭研究室编著的一本详尽解析Linux命令的参考书籍,旨在帮助用户深入理解和掌握Linux操作系统中的各种命令。这本书以扫描版的形式提供,包含PDF格式,方便读者在线阅读或下载。标签...

    Linux命令详解手册.pdf

    Linux命令详解手册是一份关于Linux操作系统下各种命令的权威指南,涵盖了系统管理、系统设置、文档编辑和压缩备份等众多方面的命令。这份手册详细列举并解释了每个命令的用途和使用方法,是Linux用户管理和维护系统...

    《Linux设备驱动开发详解-基于最新的Linux4.0内核》源码

    《Linux设备驱动开发详解-基于最新的Linux4.0内核》是一本深入探讨Linux设备驱动程序开发的专业书籍,其源码提供了丰富的实践示例,帮助读者理解如何在Linux操作系统下编写和调试驱动程序。该书涵盖了从基础概念到...

    Linux命令详解手册

    Linux命令详解手册是一本适合Linux新手和有一定基础的用户深入学习Linux命令的指南。它详细介绍了大量的Linux命令,涵盖了系统管理、系统设置、文档编辑以及压缩备份等多个方面的操作。掌握这些命令对于理解和使用...

    linux网络编程详解.pdf

    ### Linux网络编程详解知识点 #### 一、网络基础与历史 - **网络的历史**:介绍计算机网络的发展历程,包括早期的计算机网络是如何形成的,以及它们如何逐渐演变为现代互联网。 - **OSI模型**:详细解释开放系统...

    Linux设备驱动开发详解-基于最新的Linux4.0内核》配套代码.zip

    《Linux设备驱动开发详解-基于最新的Linux4.0内核》是一本深入讲解Linux设备驱动程序开发的专业书籍,配套代码存放在"learn-ldd-master-main"这个压缩包中,旨在帮助开发者理解并掌握在嵌入式Linux系统上编写驱动...

    Linux编程技术详解

    本资料"Linux编程技术详解"提供了深入理解Linux内核机制、系统调用、库函数以及编写高效Linux应用程序的原代码参考,旨在帮助读者提升Linux编程技能。 首先,我们来探讨一下Linux编程的基础。在Linux环境下,编程...

    linux设备驱动详解(宋宝华 高清 非影印版)

    《Linux设备驱动开发详解》是一本介绍Linux设备驱动开发理论、框架与实例的书,《Linux设备驱动开发详解》以Linux 2.6版本内核为蓝本,详细介绍自旋锁、信号量、完成量、中断顶/底半部、定时器、内存和I/O映射...

    linux信号详细列表

    ### Linux信号详细列表:1~31号信号详解 #### 一、概述 在Linux操作系统中,信号是一种轻量级的进程间通信机制,用于通知接收进程某个事件的发生。信号可以由硬件异常(例如除零错误)触发,也可以由软件(如kill...

    嵌入式Linux开发详解(高清PDF)

    嵌入式Linux开发是将Linux操作系统与硬件紧密结合,用于创建特定功能的设备或系统的领域。在本高清PDF教程中,华清远见提供了丰富的学习资源,旨在帮助初学者掌握嵌入式Linux开发的基础知识。以下是对各章节内容的...

Global site tag (gtag.js) - Google Analytics