zoukankan      html  css  js  c++  java
  • 15.信号通信编程

    15.信号通信编程

    在Linux系统中,信号signal的通信机制。

    信号处理流程:

        

    从上面的图可以清楚的看出信号处理的一般流程:1.选择信号 2.发送信号 3.处理信号。

    信号的类型:Linux系统支持的所有信号均定义在/usr/include/asm/signal.h里面,其中常见的信号有:

        SIGKILL:杀死进程

        SIGSTOP:暂停进程

        SIGCHLD:子进程停止或者结束时用来通知父进程。

    杀死进程:

    查看信息:man 2 kill:

    NAME

    kill - send signal to a process

    SYNOPSIS

    #include <sys/types.h>

    #include <signal.h>

    int kill(pid_t pid, int sig);

    Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

    kill(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE

    DESCRIPTION

    The kill() system call can be used to send any signal to any process

    group or process.

    If pid is positive, then signal sig is sent to the process with the ID

    specified by pid.

    If pid equals 0, then sig is sent to every process in the process group

    of the calling process.

    If pid equals -1, then sig is sent to every process for which the call-

    ing process has permission to send signals, except for process 1

    (init), but see below.

    If pid is less than -1, then sig is sent to every process in the pro-

    cess group whose ID is -pid.

    If sig is 0, then no signal is sent, but error checking is still per-

    formed; this can be used to check for the existence of a process ID or

    process group ID.

    For a process to have permission to send a signal it must either be

    privileged (under Linux: have the CAP_KILL capability), or the real or

    effective user ID of the sending process must equal the real or saved

    set-user-ID of the target process. In the case of SIGCONT it suffices

    when the sending and receiving processes belong to the same session.

    RETURN VALUE

    On success (at least one signal was sent), zero is returned. On error,

    -1 is returned, and errno is set appropriately.

    ERRORS

    EINVAL An invalid signal was specified.

    EPERM The process does not have permission to send the signal to any

    of the target processes.

    ESRCH The pid or process group does not exist. Note that an existing

    process might be a zombie, a process which already committed

    termination, but has not yet been wait(2)ed for.

    CONFORMING TO

    SVr4, 4.3BSD, POSIX.1-2001.

    NOTES

    The only signals that can be sent to process ID 1, the init process,

    are those for which init has explicitly installed signal handlers.

    This is done to assure the system is not brought down accidentally.

    POSIX.1-2001 requires that kill(-1,sig) send sig to all processes that

    the calling process may send signals to, except possibly for some

    implementation-defined system processes. Linux allows a process to

    signal itself, but on Linux the call kill(-1,sig) does not signal the

    calling process.

    POSIX.1-2001 requires that if a process sends a signal to itself, and

    the sending thread does not have the signal blocked, and no other

    thread has it unblocked or is waiting for it in sigwait(3), at least

    one unblocked signal must be delivered to the sending thread before the

    kill().

    Linux Notes

    Across different kernel versions, Linux has enforced different rules

    for the permissions required for an unprivileged process to send a sig-

    nal to another process. In kernels 1.0 to 1.2.2, a signal could be

    sent if the effective user ID of the sender matched that of the

    receiver, or the real user ID of the sender matched that of the

    receiver. From kernel 1.2.3 until 1.3.77, a signal could be sent if

    the effective user ID of the sender matched either the real or effec-

    tive user ID of the receiver. The current rules, which conform to

    POSIX.1-2001, were adopted in kernel 1.3.78.

    BUGS

    In 2.6 kernels up to and including 2.6.7, there was a bug that meant

    that when sending signals to a process group, kill() failed with the

    error EPERM if the caller did have permission to send the signal to any

    (rather than all) of the members of the process group. Notwithstanding

    this error return, the signal was still delivered to all of the pro-

    cesses for which the caller had permission to signal.

    SEE ALSO

    _exit(2), killpg(2), signal(2), sigqueue(2), tkill(2), exit(3), capa-

    bilities(7), credentials(7), signal(7)

    COLOPHON

    This page is part of release 3.22 of the Linux man-pages project. A

    description of the project, and information about reporting bugs, can

    be found at http://www.kernel.org/doc/man-pages/.

    Kill的函数原型:

    int kill(pid_t pid, int sig);

    需要包含的头文件:

    #include <sys/types.h>

    #include <signal.h>

    该函数的功能是向进程发送信号。

    返回值:成功返回0,失败返回-1.

    参数说明:

    Pid:pid>0,pid参数指向接受信号的进程,pid=0表示向同组的进程发送信号。如果pid=-1则表示进程的信号将发送给所有拥有权限的线程。除了init线程。如果pid<-1,则发送给同组的进程为pid的进程。如果sig=0,则表示没有信心传递。

    Sig:指向要发送的信号

    信号:

    查看信息:

    NAME

    signal - ANSI C signal handling

    SYNOPSIS

    #include <signal.h>

    typedef void (*sighandler_t)(int);

    sighandler_t signal(int signum, sighandler_t handler);

    DESCRIPTION

    The behavior of signal() varies across Unix versions, and has also varied his-

    torically across different versions of Linux. Avoid its use: use sigaction(2)

    instead. See Portability below.

    signal() sets the disposition of the signal signum to handler, which is either

    SIG_IGN, SIG_DFL, or the address of a programmer-defined function (a "signal

    handler").

    If the signal signum is delivered to the process, then one of the following

    happens:

    * If the disposition is set to SIG_IGN, then the signal is ignored.

    * If the disposition is set to SIG_DFL, then the default action associated

    with the signal (see signal(7)) occurs.

    * If the disposition is set to a function, then first either the disposition

    is reset to SIG_DFL, or the signal is blocked (see Portability below), and

    then handler is called with argument signum. If invocation of the handler

    caused the signal to be blocked, then the signal is unblocked upon return

    from the handler.

    The signals SIGKILL and SIGSTOP cannot be caught or ignored.

    RETURN VALUE

    signal() returns the previous value of the signal handler, or SIG_ERR on error.

    ERRORS

    EINVAL signum is invalid.

    CONFORMING TO

    C89, C99, POSIX.1-2001.

    NOTES

    The effects of signal() in a multithreaded process are unspecified.

    According to POSIX, the behavior of a process is undefined after it ignores a

    SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(2) or

    raise(3). Integer division by zero has undefined result. On some architec-

    tures it will generate a SIGFPE signal. (Also dividing the most negative inte-

    ger by -1 may generate SIGFPE.) Ignoring this signal might lead to an endless

    loop.

    See sigaction(2) for details on what happens when SIGCHLD is set to SIG_IGN.

    See signal(7) for a list of the async-signal-safe functions that can be safely

    called from inside a signal handler.

    The use of sighandler_t is a GNU extension. Various versions of libc predefine

    this type; libc4 and libc5 define SignalHandler; glibc defines sig_t and, when

    _GNU_SOURCE is defined, also sighandler_t. Without use of such a type, the

    declaration of signal() is the somewhat harder to read:

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

    Portability

    The only portable use of signal() is to set a signal's disposition to SIG_DFL

    or SIG_IGN. The semantics when using signal() to establish a signal handler

    vary across systems (and POSIX.1 explicitly permits this variation); do not use

    it for this purpose.

    POSIX.1 solved the portability mess by specifying sigaction(2), which provides

    explicit control of the semantics when a signal handler is invoked; use that

    interface instead of signal().

    In the original Unix systems, when a handler that was established using sig-

    nal() was invoked by the delivery of a signal, the disposition of the signal

    would be reset to SIG_DFL, and the system did not block delivery of further

    instances of the signal. System V also provides these semantics for signal().

    This was bad because the signal might be delivered again before the handler had

    a chance to reestablish itself. Furthermore, rapid deliveries of the same sig-

    nal could result in recursive invocations of the handler.

    BSD improved on this situation by changing the semantics of signal handling

    (but, unfortunately, silently changed the semantics when establishing a handler

    with signal()). On BSD, when a signal handler is invoked, the signal disposi-

    tion is not reset, and further instances of the signal are blocked from being

    delivered while the handler is executing.

    The situation on Linux is as follows:

    * The kernel's signal() system call provides System V semantics.

    * By default, in glibc 2 and later, the signal() wrapper function does not

    invoke the kernel system call. Instead, it calls sigaction(2) using flags

    that supply BSD semantics. This default behavior is provided as long as the

    _BSD_SOURCE feature test macro is defined. By default, _BSD_SOURCE is

    defined; it is also implicitly defined if one defines _GNU_SOURCE, and can of

    course be explicitly defined.

    On glibc 2 and later, if the _BSD_SOURCE feature test macro is not defined,

    then signal() provides System V semantics. (The default implicit definition

    of _BSD_SOURCE is not provided if one invokes gcc(1) in one of its standard

    modes (-std=xxx or -ansi) or defines various other feature test macros such

    as _POSIX_SOURCE, _XOPEN_SOURCE, or _SVID_SOURCE; see fea-

    ture_test_macros(7).)

    * The signal() function in Linux libc4 and libc5 provide System V semantics.

    If one on a libc5 system includes <bsd/signal.h> instead of <signal.h>, then

    signal() provides BSD semantics.

    SEE ALSO

    kill(1), alarm(2), kill(2), killpg(2), pause(2), sigaction(2), signalfd(2),

    sigpending(2), sigprocmask(2), sigqueue(2), sigsuspend(2), bsd_signal(3),

    raise(3), siginterrupt(3), sigsetops(3), sigvec(3), sysv_signal(3), fea-

    ture_test_macros(7), signal(7)

    COLOPHON

    This page is part of release 3.22 of the Linux man-pages project. A descrip-

    tion of the project, and information about reporting bugs, can be found at

    http://www.kernel.org/doc/man-pages/.

    函数名:signal。

    函数原型:

    typedef void (*sighandler_t)(int);

    sighandler_t signal(int signum, sighandler_t handler);

    该函数的功能:设置信号的处理方式。

    需要的头文件:signal.h

    返回值:成功:返回处理函数指针。失败:返回SIG_ERR.

    参数:

    Signum:要处理的信号。

    Handler:对应信号的处理方式,可以取值:

        SIG_IGN:忽视这个信号,不处理。

        SIG_DFL:交给内核来处理。

        用户自定义的函数:自己定义函数来处理:typedef void (*sighandler_t)(int);

    暂停信号:

    函数的原型pause:

    查看文档:

    NAME

    pause - wait for signal

    SYNOPSIS

    #include <unistd.h>

    int pause(void);

    DESCRIPTION

    pause() causes the calling process (or thread) to sleep until a signal

    is delivered that either terminates the process or causes the invoca-

    tion of a signal-catching function.

    RETURN VALUE

    pause() only returns when a signal was caught and the signal-catching

    function returned. In this case pause() returns -1, and errno is set

    to EINTR.

    ERRORS

    EINTR a signal was caught and the signal-catching function returned.

    CONFORMING TO

    SVr4, 4.3BSD, POSIX.1-2001.

    SEE ALSO

    kill(2), select(2), signal(2), sigsuspend(2)

    COLOPHON

    This page is part of release 3.22 of the Linux man-pages project. A

    description of the project, and information about reporting bugs, can

    be found at http://www.kernel.org/doc/man-pages/.

    该函数的原型:

    int pause(void);

    该函数没有参数,功能是等待一个进程,直到收到信号。

    下面我们来实现:A,B进程通信的机制。

    A进程:发送signal到B进程。

    B进程:B进程设置signal信号的处理方式,然后等待。

    编写B:asignal.c接受来之A的信号:

    asignal.c:

    #include <signal.h>

    #include <unistd.h>

    void myfunc(int a){

        printf("process B received signal! ");

    }

    void main(){

        signal(SIGINT,myfunc);

        pause();

    }

    编译运行:

    运行完后进入等待状态。

    然后在命令行发送一个信号:

    先执行ps aux:

    知道进程号为3588.

    然后在另外一个终端执行:

    应用程序收到信号:

    我们看到进程收到了信号输出了信息。

    接下来我们来编写A程序:aasignal.c:

    #include <sys/types.h>

    #include <signal.h>

    #include <stdio.h>

    void main(int argc, char **argv){

        pid_t pid;

        pid = atoi(argv[1]);//change string to integer

        kill(pid,SIGINT);

    }

    运行的结果:

    通过上面的例子我们知道:当我们运行了A进程后,B进程收到了信号,打印出来了信息。并且我们在A进程进行了自行出理。这样我们就可以实现进程间的通信机制了。

  • 相关阅读:
    BIO、NIO、AIO有什么区别?
    java中IO流有哪些?
    List、Map、Set 三个接口,存取元素时,各有什么特点?
    Vector、ArrayList、LinkedList 的存储性能和特性?
    Java.util.Map的常用实现类有哪些?
    Java自学指南六、查一手资料
    虚拟机中Lvs配置
    m2014-software->Word2010发布博客文章至Cnblogs
    m2014-c->c模拟java的hashmap容器类
    m2014_c->c语言容器类工具列
  • 原文地址:https://www.cnblogs.com/FORFISH/p/5188657.html
Copyright © 2011-2022 走看看