Linux系统开发6 信号

时间:2022-10-21 18:38:24

本文谢绝转载,原文来自http://990487026.blog.51cto.com


《大纲》
Linux系统开发6 信号
linux系统有64种信号
signal man文档
终端按键信号
ctrl +c SIGIN
ctrl +z SIGTSTP
ctrl +\ SIGQUIT

硬件产生信号
浮点数例外信号 
访问非法内存

kill()函数
信号与权限
kill()函数的pid 与返回值
信号产生原因

raise() 信号
abort() 信号
alarm() 信号
收到信号的默认操作
信号阻塞 屏蔽<ctrl+c>,<ctrl+z>,<ctrl+\>
解除信号的阻塞
信号捕捉 sa_handler 自定义函数 方式捕捉crtl + c
sa_handler 设定为默认 默认处理ctrl+c
sa_handler 设定为忽略 ctrl+c
处理信号的时候再来一次信号,并不会嵌套,
sigaddset() 当进入信号函数的调用时
1,没有屏蔽 ctrl+\ 信号的时候,执行信号函数会响应ctrl+\操作
2,屏蔽 ctrl+\ 信号的时候,执行信号函数不会响应ctrl+\,等运行结束后才会响应

SIGUSR1用户自定义信号
C 标准库函数,信号捕捉函数
system函数,集成与fork() exit() wait()一体的函数 
可重入 不可重入函数
Linux下的可重入安全函数
pause()系统挂起,等待信号的来临
pause()系统挂起,如果是忽略操作就忽略
利用pause() 与 信号 实现my_sleep()函数
my_sleep()函数 时序竞态问题
my_sleep增强 sigsuspend避免了时序竞争 

什么是sig_atomic_t数据类型 
SIGCHLD 信号产生的条件
用信号回收子进程
作业:


linux系统有64种信号

我们只讨论系统的前32种信号(1--31)

后面32种是硬件驱动自定义信号

chunli@ubuntu:~$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL10) SIGUSR111) SIGSEGV12) SIGUSR213) SIGPIPE14) SIGALRM15) SIGTERM16) SIGSTKFLT17) SIGCHLD18) SIGCONT19) SIGSTOP20) SIGTSTP21) SIGTTIN22) SIGTTOU23) SIGURG24) SIGXCPU25) SIGXFSZ26) SIGVTALRM27) SIGPROF28) SIGWINCH29) SIGIO30) SIGPWR31) SIGSYS34) SIGRTMIN35) SIGRTMIN+136) SIGRTMIN+237) SIGRTMIN+338) SIGRTMIN+439) SIGRTMIN+540) SIGRTMIN+641) SIGRTMIN+742) SIGRTMIN+843) SIGRTMIN+944) SIGRTMIN+1045) SIGRTMIN+1146) SIGRTMIN+1247) SIGRTMIN+1348) SIGRTMIN+1449) SIGRTMIN+1550) SIGRTMAX-1451) SIGRTMAX-1352) SIGRTMAX-1253) SIGRTMAX-1154) SIGRTMAX-1055) SIGRTMAX-956) SIGRTMAX-857) SIGRTMAX-758) SIGRTMAX-659) SIGRTMAX-560) SIGRTMAX-461) SIGRTMAX-362) SIGRTMAX-263) SIGRTMAX-164) SIGRTMAXchunli@ubuntu:~$


signal man文档

chunli@ubuntu:~$ man 7 signalSIGNAL(7)                     Linux Programmer's Manual                     SIGNAL(7)NAME       signal - overview of signalsDESCRIPTION       Linux  supports  both  POSIX reliable signals (hereinafter "standard signals")       and POSIX real-time signals.   Signal dispositions       Each signal has a  current  disposition,  which  determines  how  the  process       behaves when it is delivered the signal.       The  entries  in  the  "Action" column of the tables below specify the default       disposition for each signal, as follows:       Term   Default action is to terminate the process.       Ign    Default action is to ignore the signal.       Core   Default action is to terminate the process and dump core (see core(5)).       Stop   Default action is to stop the process.       Cont   Default action is to continue the process if it is currently stopped.       A process can change the disposition of a signal using  sigaction(2)  or  sig�\       nal(2).   (The latter is less portable when establishing a signal handler; see       signal(2) for details.)  Using these system calls, a process can elect one  of       the  following  behaviors  to  occur  on  delivery  of the signal: perform the       default action; ignore the signal; or catch the signal with a signal  handler,       a programmer-defined function that is automatically invoked when the signal is       delivered.  (By default, the signal handler is invoked on the  normal  process       stack.   It  is  possible to arrange that the signal handler uses an alternate       stack; see sigaltstack(2) for a discussion of how to do this and when it might       be useful.)       The signal disposition is a per-process attribute: in a multithreaded applica�\       tion, the disposition of a particular signal is the same for all threads.       A child created via fork(2) inherits a copy of its  parent's  signal  disposi�\       tions.   During an execve(2), the dispositions of handled signals are reset to       the default; the dispositions of ignored signals are left unchanged.   Sending a signal       The following system calls and library functions allow the caller  to  send  a       signal:       raise(3)        Sends a signal to the calling thread.       kill(2)         Sends  a  signal  to  a specified process, to all members of a                       specified process group, or to all processes on the system.       killpg(2)       Sends a signal to all of the members of  a  specified  process                       group.       pthread_kill(3) Sends a signal to a specified POSIX thread in the same process                       as the caller.       tgkill(2)       Sends a  signal  to  a  specified  thread  within  a  specific                       process.    (This   is  the  system  call  used  to  implement                       pthread_kill(3).)       sigqueue(3)     Sends a real-time signal with accompanying data to a specified                       process.   Waiting for a signal to be caught       The  following system calls suspend execution of the calling process or thread       until a signal is caught (or an unhandled signal terminates the process):       pause(2)        Suspends execution until any signal is caught.       sigsuspend(2)   Temporarily changes the signal mask (see below)  and  suspends                       execution until one of the unmasked signals is caught.   Synchronously accepting a signal       Rather  than asynchronously catching a signal via a signal handler, it is pos�\       sible to synchronously accept the signal, that is, to  block  execution  until       the  signal  is delivered, at which point the kernel returns information about       the signal to the caller.  There are two general ways to do this:       * sigwaitinfo(2), sigtimedwait(2), and sigwait(3) suspend execution until  one         of the signals in a specified set is delivered.  Each of these calls returns         information about the delivered signal.       * signalfd(2) returns a file descriptor that can be used to  read  information         about signals that are delivered to the caller.  Each read(2) from this file         descriptor blocks until one of the signals in the set specified in the  sig�\         nalfd(2)  call  is  delivered to the caller.  The buffer returned by read(2)         contains a structure describing the signal.   Signal mask and pending signals       A signal may be blocked, which means that it will not be delivered until it is       later  unblocked.  Between the time when it is generated and when it is deliv�\       ered a signal is said to be pending.       Each thread in a process has an independent signal mask, which  indicates  the       set of signals that the thread is currently blocking.  A thread can manipulate       its signal mask using pthread_sigmask(3).  In  a  traditional  single-threaded       application, sigprocmask(2) can be used to manipulate the signal mask.       A  child  created via fork(2) inherits a copy of its parent's signal mask; the       signal mask is preserved across execve(2).       A signal may be generated (and thus pending) for a process as a  whole  (e.g.,       when sent using kill(2)) or for a specific thread (e.g., certain signals, such       as SIGSEGV and SIGFPE, generated as a  consequence  of  executing  a  specific       machine-language instruction are thread directed, as are signals targeted at a       specific thread using pthread_kill(3)).   A  process-directed  signal  may  be       delivered  to  any  one of the threads that does not currently have the signal       blocked.  If more than one of the threads has the signal unblocked,  then  the       kernel chooses an arbitrary thread to which to deliver the signal.       A  thread  can  obtain  the set of signals that it currently has pending using       sigpending(2).  This set will consist of the  union  of  the  set  of  pending       process-directed  signals  and  the  set  of  signals  pending for the calling       thread.       A child created via fork(2) initially has an empty  pending  signal  set;  the       pending signal set is preserved across an execve(2).   Standard signals       Linux  supports the standard signals listed below.  Several signal numbers are       architecture-dependent, as indicated in the "Value" column.  (Where three val�\       ues  are given, the first one is usually valid for alpha and sparc, the middle       one for x86, arm, and most other architectures, and the  last  one  for  mips.       (Values  for parisc are not shown; see the Linux kernel source for signal num�\       bering on that architecture.)  A - denotes that a signal is absent on the cor�\       responding architecture.)       First the signals described in the original POSIX.1-1990 standard.       Signal     Value     Action   Comment       ──────────────────────────────────────────────────────────────────────       SIGHUP        1       Term    Hangup detected on controlling terminal                                     or death of controlling process       SIGINT        2       Term    Interrupt from keyboard       SIGQUIT       3       Core    Quit from keyboard       SIGILL        4       Core    Illegal Instruction       SIGABRT       6       Core    Abort signal from abort(3)       SIGFPE        8       Core    Floating point exception       SIGKILL       9       Term    Kill signal       SIGSEGV      11       Core    Invalid memory reference       SIGPIPE      13       Term    Broken pipe: write to pipe with no                                     readers       SIGALRM      14       Term    Timer signal from alarm(2)       SIGTERM      15       Term    Termination signal       SIGUSR1   30,10,16    Term    User-defined signal 1       SIGUSR2   31,12,17    Term    User-defined signal 2       SIGCHLD   20,17,18    Ign     Child stopped or terminated       SIGCONT   19,18,25    Cont    Continue if stopped       SIGSTOP   17,19,23    Stop    Stop process       SIGTSTP   18,20,24    Stop    Stop typed at terminal       SIGTTIN   21,21,26    Stop    Terminal input for background process       SIGTTOU   22,22,27    Stop    Terminal output for background process       The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.       Next  the  signals not in the POSIX.1-1990 standard but described in SUSv2 and       POSIX.1-2001.       Signal       Value     Action   Comment       ────────────────────────────────────────────────────────────────────       SIGBUS      10,7,10     Core    Bus error (bad memory access)       SIGPOLL                 Term    Pollable event (Sys V).                                       Synonym for SIGIO       SIGPROF     27,27,29    Term    Profiling timer expired       SIGSYS      12,31,12    Core    Bad argument to routine (SVr4)       SIGTRAP        5        Core    Trace/breakpoint trap       SIGURG      16,23,21    Ign     Urgent condition on socket (4.2BSD)       SIGVTALRM   26,26,28    Term    Virtual alarm clock (4.2BSD)       SIGXCPU     24,24,30    Core    CPU time limit exceeded (4.2BSD)       SIGXFSZ     25,25,31    Core    File size limit exceeded (4.2BSD)       Up to and including Linux 2.2,  the  default  behavior  for  SIGSYS,  SIGXCPU,       SIGXFSZ, and (on architectures other than SPARC and MIPS) SIGBUS was to termi�\       nate the process (without a core dump).   (On  some  other  UNIX  systems  the       default  action  for SIGXCPU and SIGXFSZ is to terminate the process without a       core dump.)  Linux 2.4 conforms to the  POSIX.1-2001  requirements  for  these       signals, terminating the process with a core dump.       Next various other signals.       Signal       Value     Action   Comment       ────────────────────────────────────────────────────────────────────       SIGIOT         6        Core    IOT trap. A synonym for SIGABRT       SIGEMT       7,-,7      Term       SIGSTKFLT    -,16,-     Term    Stack fault on coprocessor (unused)       SIGIO       23,29,22    Term    I/O now possible (4.2BSD)       SIGCLD       -,-,18     Ign     A synonym for SIGCHLD       SIGPWR      29,30,19    Term    Power failure (System V)       SIGINFO      29,-,-             A synonym for SIGPWR       SIGLOST      -,-,-      Term    File lock lost (unused)       SIGWINCH    28,28,20    Ign     Window resize signal (4.3BSD, Sun)       SIGUNUSED    -,31,-     Core    Synonymous with SIGSYS       (Signal 29 is SIGINFO / SIGPWR on an alpha but SIGLOST on a sparc.)       SIGEMT  is  not  specified  in  POSIX.1-2001, but nevertheless appears on most       other UNIX systems, where its default action is  typically  to  terminate  the       process with a core dump.       SIGPWR  (which  is  not  specified  in  POSIX.1-2001)  is typically ignored by       default on those other UNIX systems where it appears.       SIGIO (which is not specified in POSIX.1-2001) is ignored by default  on  sev�\       eral other UNIX systems.       Where defined, SIGUNUSED is synonymous with SIGSYS on most architectures.   Real-time signals       Starting  with  version  2.2,  Linux  supports real-time signals as originally       defined  in  the  POSIX.1b  real-time  extensions   (and   now   included   in       POSIX.1-2001).   The  range  of  supported real-time signals is defined by the       macros SIGRTMIN and SIGRTMAX.  POSIX.1-2001 requires  that  an  implementation       support at least _POSIX_RTSIG_MAX (8) real-time signals.       The  Linux kernel supports a range of 33 different real-time signals, numbered       32 to 64.  However, the glibc POSIX threads implementation internally uses two       (for  NPTL)  or  three (for LinuxThreads) real-time signals (see pthreads(7)),       and adjusts the value of SIGRTMIN suitably (to 34 or 35).  Because  the  range       of  available real-time signals varies according to the glibc threading imple�\       mentation (and this variation can occur at run time according to the available       kernel  and  glibc),  and  indeed the range of real-time signals varies across       UNIX systems, programs should never refer to  real-time  signals  using  hard-       coded  numbers, but instead should always refer to real-time signals using the       notation SIGRTMIN+n, and include suitable (run-time)  checks  that  SIGRTMIN+n       does not exceed SIGRTMAX.       Unlike  standard  signals,  real-time signals have no predefined meanings: the       entire set of real-time signals can be used for application-defined purposes.       The default action for an unhandled  real-time  signal  is  to  terminate  the       receiving process.       Real-time signals are distinguished by the following:       1.  Multiple  instances  of  real-time signals can be queued.  By contrast, if           multiple instances of a standard signal are delivered while that signal is           currently blocked, then only one instance is queued.       2.  If  the signal is sent using sigqueue(3), an accompanying value (either an           integer or a pointer) can be sent  with  the  signal.   If  the  receiving           process establishes a handler for this signal using the SA_SIGINFO flag to           sigaction(2), then it can obtain this data via the si_value field  of  the           siginfo_t  structure  passed  as the second argument to the handler.  Fur�\           thermore, the si_pid and si_uid fields of this structure can  be  used  to           obtain the PID and real user ID of the process sending the signal.       3.  Real-time signals are delivered in a guaranteed order.  Multiple real-time           signals of the same type are delivered in the order they  were  sent.   If           different  real-time  signals  are  sent  to a process, they are delivered           starting with the lowest-numbered  signal.   (I.e.,  low-numbered  signals           have  highest  priority.)   By  contrast, if multiple standard signals are           pending for a process, the order in which they are delivered  is  unspeci�\           fied.       If both standard and real-time signals are pending for a process, POSIX leaves       it unspecified which is delivered first.  Linux, like many  other  implementa�\       tions, gives priority to standard signals in this case.       According    to    POSIX,   an   implementation   should   permit   at   least       _POSIX_SIGQUEUE_MAX (32) real-time signals to be queued to  a  process.   How�\       ever,  Linux  does  things differently.  In kernels up to and including 2.6.7,       Linux imposes a system-wide limit on the number of  queued  real-time  signals       for  all processes.  This limit can be viewed and (with privilege) changed via       the /proc/sys/kernel/rtsig-max file.  A related file,  /proc/sys/kernel/rtsig-       nr,  can  be used to find out how many real-time signals are currently queued.       In Linux 2.6.8, these /proc interfaces were replaced by the  RLIMIT_SIGPENDING       resource limit, which specifies a per-user limit for queued signals; see setr�\       limit(2) for further details.       The addition or real-time signals required the  widening  of  the  signal  set       structure  (sigset_t)  from 32 to 64 bits.  Consequently, various system calls       were superseded by new system calls that supported  the  larger  signal  sets.       The old and new system calls are as follows:       Linux 2.0 and earlier   Linux 2.2 and later       sigaction(2)            rt_sigaction(2)       sigpending(2)           rt_sigpending(2)       sigprocmask(2)          rt_sigprocmask(2)       sigreturn(2)            rt_sigreturn(2)       sigsuspend(2)           rt_sigsuspend(2)       sigtimedwait(2)         rt_sigtimedwait(2)   Async-signal-safe functions       A signal handler function must be very careful, since processing elsewhere may       be interrupted at some arbitrary point in the execution of the program.  POSIX       has  the  concept of "safe function".  If a signal interrupts the execution of       an unsafe function, and handler calls an unsafe function, then the behavior of       the program is undefined.       POSIX.1-2004  (also known as POSIX.1-2001 Technical Corrigendum 2) requires an       implementation to guarantee that the following functions can be safely  called       inside a signal handler:           _Exit()           _exit()           abort()           accept()           access()           aio_error()           aio_return()           aio_suspend()           alarm()           bind()           cfgetispeed()           cfgetospeed()           cfsetispeed()           cfsetospeed()           chdir()           chmod()           chown()           clock_gettime()           close()           connect()           creat()           dup()           dup2()           execle()           execve()           fchmod()           fchown()           fcntl()           fdatasync()           fork()           fpathconf()           fstat()           fsync()           ftruncate()           getegid()           geteuid()           getgid()           getgroups()           getpeername()           getpgrp()           getpid()           getppid()           getsockname()           getsockopt()           getuid()           kill()           link()           listen()           lseek()           lstat()           mkdir()           mkfifo()           open()           pathconf()           pause()           pipe()           poll()           posix_trace_event()           pselect()           raise()           read()           readlink()           recv()           recvfrom()           recvmsg()           rename()           rmdir()           select()           sem_post()           send()           sendmsg()           sendto()           setgid()           setpgid()           setsid()           setsockopt()           setuid()           shutdown()           sigaction()           sigaddset()           sigdelset()           sigemptyset()           sigfillset()           sigismember()           signal()           sigpause()           sigpending()           sigprocmask()           sigqueue()           sigset()           sigsuspend()           sleep()           sockatmark()           socket()           socketpair()           stat()           symlink()           sysconf()           tcdrain()           tcflow()           tcflush()           tcgetattr()           tcgetpgrp()           tcsendbreak()           tcsetattr()           tcsetpgrp()           time()           timer_getoverrun()           timer_gettime()           timer_settime()           times()           umask()           uname()           unlink()           utime()           wait()           waitpid()           write()       POSIX.1-2008  removes  fpathconf(),  pathconf(),  and sysconf() from the above       list, and adds the following functions:           execl()           execv()           faccessat()           fchmodat()           fchownat()           fexecve()           fstatat()           futimens()           linkat()           mkdirat()           mkfifoat()           mknod()           mknodat()           openat()           readlinkat()           renameat()           symlinkat()           unlinkat()           utimensat()           utimes()       POSIX.1-2008 Technical Corrigendum 1 (2013) adds the following functions:           fchdir()           pthread_kill()           pthread_self()           pthread_sigmask()   Interruption of system calls and library functions by signal handlers       If a signal handler is invoked while a system call or library function call is       blocked, then either:       * the call is automatically restarted after the signal handler returns; or       * the call fails with the error EINTR.       Which  of  these  two behaviors occurs depends on the interface and whether or       not the signal handler was established using the SA_RESTART flag  (see  sigac�\       tion(2)).  The details vary across UNIX systems; below, the details for Linux.       If  a blocked call to one of the following interfaces is interrupted by a sig�\       nal handler, then the call will be automatically restarted  after  the  signal       handler  returns if the SA_RESTART flag was used; otherwise the call will fail       with the error EINTR:           * read(2), readv(2), write(2), writev(2), and  ioctl(2)  calls  on  "slow"             devices.   A  "slow"  device  is one where the I/O call may block for an             indefinite time, for example, a terminal, pipe, or socket.   If  an  I/O             call  on  a slow device has already transferred some data by the time it             is interrupted by a signal handler, then the call will return a  success             status (normally, the number of bytes transferred).  Note that a (local)             disk is not a slow device according to this definition;  I/O  operations             on disk devices are not interrupted by signals.           * open(2), if it can block (e.g., when opening a FIFO; see fifo(7)).           * wait(2), wait3(2), wait4(2), waitid(2), and waitpid(2).           * Socket   interfaces:   accept(2),   connect(2),   recv(2),  recvfrom(2),             recvmmsg(2), recvmsg(2), send(2), sendto(2), and  sendmsg(2),  unless  a             timeout has been set on the socket (see below).           * File  locking  interfaces:  flock(2)  and  the F_SETLKW and F_OFD_SETLKW             operations of fcntl(2)           * POSIX  message  queue  interfaces:  mq_receive(3),   mq_timedreceive(3),             mq_send(3), and mq_timedsend(3).           * futex(2)  FUTEX_WAIT (since Linux 2.6.22; beforehand, always failed with             EINTR).           * getrandom(2).           * pthread_mutex_lock(3), pthread_cond_wait(3), and related APIs.           * futex(2) FUTEX_WAIT_BITSET.           * POSIX semaphore  interfaces:  sem_wait(3)  and  sem_timedwait(3)  (since             Linux 2.6.22; beforehand, always failed with EINTR).       The following interfaces are never restarted after being interrupted by a sig�\       nal handler, regardless of the use of SA_RESTART; they always  fail  with  the       error EINTR when interrupted by a signal handler:           * "Input"  socket interfaces, when a timeout (SO_RCVTIMEO) has been set on             the  socket  using  setsockopt(2):  accept(2),   recv(2),   recvfrom(2),             recvmmsg(2) (also with a non-NULL timeout argument), and recvmsg(2).           * "Output" socket interfaces, when a timeout (SO_RCVTIMEO) has been set on             the socket using  setsockopt(2):  connect(2),  send(2),  sendto(2),  and             sendmsg(2).           * Interfaces  used to wait for signals: pause(2), sigsuspend(2), sigtimed�\             wait(2), and sigwaitinfo(2).           * File descriptor multiplexing interfaces: epoll_wait(2),  epoll_pwait(2),             poll(2), ppoll(2), select(2), and pselect(2).           * System  V  IPC  interfaces: msgrcv(2), msgsnd(2), semop(2), and semtime�\             dop(2).           * Sleep interfaces: clock_nanosleep(2), nanosleep(2), and usleep(3).           * read(2) from an inotify(7) file descriptor.           * io_getevents(2).       The sleep(3) function is also never restarted if interrupted by a handler, but       gives a success return: the number of seconds remaining to sleep.   Interruption of system calls and library functions by stop signals       On  Linux, even in the absence of signal handlers, certain blocking interfaces       can fail with the error EINTR after the process is stopped by one of the  stop       signals  and  then  resumed  via  SIGCONT.  This behavior is not sanctioned by       POSIX.1, and doesn't occur on other systems.       The Linux interfaces that display this behavior are:           * "Input" socket interfaces, when a timeout (SO_RCVTIMEO) has been set  on             the   socket   using  setsockopt(2):  accept(2),  recv(2),  recvfrom(2),             recvmmsg(2) (also with a non-NULL timeout argument), and recvmsg(2).           * "Output" socket interfaces, when a timeout (SO_RCVTIMEO) has been set on             the  socket  using  setsockopt(2):  connect(2),  send(2), sendto(2), and             sendmsg(2), if a send timeout (SO_SNDTIMEO) has been set.           * epoll_wait(2), epoll_pwait(2).           * semop(2), semtimedop(2).           * sigtimedwait(2), sigwaitinfo(2).           * read(2) from an inotify(7) file descriptor.           * Linux  2.6.21  and  earlier:  futex(2)   FUTEX_WAIT,   sem_timedwait(3),             sem_wait(3).           * Linux 2.6.8 and earlier: msgrcv(2), msgsnd(2).           * Linux 2.4 and earlier: nanosleep(2).CONFORMING TO       POSIX.1, except as noted.SEE ALSO       kill(1),  getrlimit(2),  kill(2),  killpg(2), restart_syscall(2), rt_sigqueue�\       info(2),  setitimer(2),  setrlimit(2),  sgetmask(2),   sigaction(2),   sigalt�\       stack(2),   signal(2),  signalfd(2),  sigpending(2),  sigprocmask(2),  sigsus�\       pend(2),  sigwaitinfo(2),  abort(3),  bsd_signal(3),   longjmp(3),   raise(3),       pthread_sigqueue(3),  sigqueue(3),  sigset(3),  sigsetops(3),  sigvec(3), sig�\       wait(3), strsignal(3), sysv_signal(3), core(5), proc(5), nptl(7), pthreads(7),       sigevent(7)COLOPHON       This  page is part of release 4.04 of the Linux man-pages project.  A descrip�\       tion of the project, information about reporting bugs, and the latest  version       of this page, can be found at http://www.kernel.org/doc/man-pages/.Linux                                 2015-12-05                            SIGNAL(7)chunli@ubuntu:~$



终端按键 够产生的信号:

ctrl +c SIGIN

ctrl +z SIGTSTP

ctrl +\ SIGQUIT

chunli@ubuntu:~/linux_c/信号$ cat main.c #include <unistd.h>int main(){while(1){sleep(1);}}



程序终止信号:ctrl +c SIGINchunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./appctrl + c 发生终止信号^Cchunli@ubuntu:~/linux_c/信号$


程序停止信号 ctrl +z SIGTSTPchunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./appctrl + z 发生停止信号相当于  20) SIGTSTP^Z[1]+  已停止               ./appchunli@ubuntu:~/linux_c/信号$ bg 1[1]+ ./app &chunli@ubuntu:~/linux_c/信号$ 可以看到这个程序在后台运行chunli@ubuntu:~/linux_c/信号$ ps ajx  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND  6362   6455   6455   6362 pts/9      6456 S     1000   0:00 ./app发送 SIGTSTP信号chunli@ubuntu:~/linux_c/信号$ kill -20 6455chunli@ubuntu:~/linux_c/信号$ jobs[1]+  已停止               ./app


程序退出信号 ctrl +\ SIGQUITchunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app^\退出 (核心已转储)


硬件产生信号

浮点数例外信号  CPU不能除0运算 8)SIGFPE

chunli@ubuntu:~/linux_c/信号$ cat main.c #include <unistd.h>int main(){int a = 5;int b = 0;a = a/b;}chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app浮点数例外 (核心已转储)chunli@ubuntu:~/linux_c/信号$


访问非法内存,段错误 11)SIGSEGV信号,

chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app段错误 (核心已转储)chunli@ubuntu:~/linux_c/信号$ cat main.c #include <unistd.h>int main(){char *p = "Hello World!";*p = 0;}chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app段错误 (核心已转储)chunli@ubuntu:~/linux_c/信号$




kill() 函数

程序1 ,运行在后台

chunli@ubuntu:~/linux_c/信号$ cat while.c #include <unistd.h>int main(){while(1){sleep(1);}}编译,放到后台执行chunli@ubuntu:~/linux_c/信号$ gcc while.c -o while && ./while &[1] 6829chunli@ubuntu:~/linux_c/信号$ ps aux | grep whilechunli     6835  0.0  0.0   4224   648 pts/9    S    11:14   0:00 ./whilechunli@ubuntu:~/linux_c/信号$ ps ajx | grep while  6829   6835   6829   6362 pts/9      6838 S     1000   0:00 ./while



程序2 ,kill函数

chunli@ubuntu:~/linux_c/信号$ cat main.c #include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <signal.h>int main(int argc,char **argv ,char **env){if(argc < 3){printf("请输入进程PID、信号\n");exit(1);}// int kill(pid_t pid, int sig);int ret = kill((pid_t)atoi(argv[1]),atoi(argv[2]));if(ret == -1){perror("kill");exit(2);}return ret;}chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app 请输入进程PID、信号chunli@ubuntu:~/linux_c/信号$


用函数,杀死这个进程

chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app 6835 9chunli@ubuntu:~/linux_c/信号$ -bash: 行 190:  6835 已杀死               ./while[1]+  退出 137              gcc while.c -o while && ./whilechunli@ubuntu:~/linux_c/信号$


再试一次,发送段错误信号

chunli@ubuntu:~/linux_c/信号$ gcc while.c -o while && ./while &[1] 6858chunli@ubuntu:~/linux_c/信号$ gcc main.c -o app &&  ./app 6858 11chunli@ubuntu:~/linux_c/信号$ [1]+  段错误               (核心已转储) gcc while.c -o while && ./whilechunli@ubuntu:~/linux_c/信号$


信号与权限

普通用户不可以越权操作杀死别人的信号

chunli@ubuntu:~/linux_c/信号$ ps aux | grep root|head -n 5USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDroot          1  0.0  0.6 119904  6184 ?        Ss   08:56   0:03 /sbin/init splashroot          2  0.0  0.0      0     0 ?        S    08:56   0:00 [kthreadd]root          3  0.0  0.0      0     0 ?        S    08:56   0:00 [ksoftirqd/0]root          5  0.0  0.0      0     0 ?        S<   08:56   0:00 [kworker/0:0H]root          7  0.0  0.0      0     0 ?        S    08:56   0:01 [rcu_sched]chunli@ubuntu:~/linux_c/信号$ kill -9 1-bash: kill: (1) - 不允许的操作chunli@ubuntu:~/linux_c/信号$



kill()函数的pid 与返回值

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 calling 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 process group whose ID is -pid.       If sig is 0, then no signal is sent, but error checking is still performed; 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.  (Historically, the rules were different; see NOTES.)RETURN VALUE       On success (at least one signal was sent), zero is returned.  On error, -1 is returned, and errno is set appropriately.       pid > 0sig发送给ID为pid的进程pid == 0sig发送给与发送进程同组的所有进程pid < 0sig发送给组ID为|-pid|的进程,并且发送进程具有向其发送信号的权限pid == -1sig发送给发送进程有权限向他们发送信号的系统上的所有进程sig为0时,用于检测,特定为pid进程是否存在,如不存在,返回-1。



信号产生原因



1) SIGHUP:当用户退出shell时,由该shell启动的所有进程将收到这个信号,默认动作为终止进程

2)SIGINT:当用户按下了<Ctrl+C>组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止里程。

3)SIGQUIT:当用户按下<ctrl+\>组合键时产生该信号,用户终端向正在运行中的由该终端启动的程序发出些信号。默认动作为终止进程。

4)SIGILL:CPU检测到某进程执行了非法指令。默认动作为终止进程并产生core文件

5)SIGTRAP:该信号由断点指令或其他 trap指令产生。默认动作为终止里程 并产生core文件。

6) SIGABRT:调用abort函数时产生该信号。默认动作为终止进程并产生core文件。

7)SIGBUS:非法访问内存地址,包括内存对齐出错,默认动作为终止进程并产生core文件。

8)SIGFPE:在发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等所有的算法错误。默认动作为终止进程并产生core文件。

9)SIGKILL:无条件终止进程。本信号不能被忽略,处理和阻塞。默认动作为终止进程。它向系统管理员提供了可以杀死任何进程的方法。

10)SIGUSE1:用户定义 的信号。即程序员可以在程序中定义并使用该信号。默认动作为终止进程。

11)SIGSEGV:指示进程进行了无效内存访问。默认动作为终止进程并产生core文件。

12)SIGUSR2:这是另外一个用户自定义信号 ,程序员可以在程序中定义 并使用该信号。默认动作为终止进程。1

13)SIGPIPE:Broken pipe向一个没有读端的管道写数据。默认动作为终止进程。

14) SIGALRM:定时器超时,超时的时间 由系统调用alarm设置。默认动作为终止进程。

15)SIGTERM:程序结束信号,与SIGKILL不同的是,该信号可以被阻塞和终止。通常用来要示程序正常退出。执行shell命令Kill时,缺省产生这个信号。默认动作为终止进程。

16)SIGCHLD:子进程结束时,父进程会收到这个信号。默认动作为忽略这个信号。

17)SIGCONT:停止进程的执行。信号不能被忽略,处理和阻塞。默认动作为终止进程。

18)SIGTTIN:后台进程读终端控制台。默认动作为暂停进程。

19)SIGTSTP:停止进程的运行。按下<ctrl+z>组合键时发出这个信号。默认动作为暂停进程。

21)SIGTTOU:该信号类似于SIGTTIN,在后台进程要向终端输出数据时发生。默认动作为暂停进程。

22)SIGURG:套接字上有紧急数据时,向当前正在运行的进程发出些信号,报告有紧急数据到达。如网络带外数据到达,默认动作为忽略该信号。

23)SIGXFSZ:进程执行时间超过了分配给该进程的CPU时间 ,系统产生该信号并发送给该进程。默认动作为终止进程。

24)SIGXFSZ:超过文件的最大长度设置。默认动作为终止进程。

25)SIGVTALRM:虚拟时钟超时时产生该信号。类似于SIGALRM,但是该信号只计算该进程占用CPU的使用时间。默认动作为终止进程。

26)SGIPROF:类似于SIGVTALRM,它不公包括该进程占用CPU时间还包括执行系统调用时间。默认动作为终止进程。

27)SIGWINCH:窗口变化大小时发出。默认动作为忽略该信号。

28)SIGIO:此信号向进程指示发出了一个异步IO事件。默认动作为忽略。

29)SIGPWR:关机。默认动作为终止进程。

30)SIGSYS:无效的系统调用。默认动作为终止进程并产生core文件。

31)SIGRTMIN~(64)SIGRTMAX:LINUX的实时信号,它们没有固定的含义(可以由用户自定义)。所有的实时信号的默认动作都为终止进程。



raise() abort()

kill函数或kill命令 不过,kill向调用者返回测试结果时,原来存在的被测试进程可能刚终止


自己给自己发信号

int raise(int sig)

自己终止

void abort(void)


alarm()定时器


某种软件条件已发生 定时器alarm到时,每个进程只有一个定时器

unsigned int alarm(unsigned int seconds)


计算 计算机的性能

chunli@ubuntu:~/linux_c/信号$ cat alarm.c #include <unistd.h>#include <stdio.h>int main(void){int counter;alarm(1);for(counter=0; 1; counter++)printf("counter=%d \n", counter);return 0;}countechunli@ubuntu:~/linux_c/信号$ gcc -o alarm alarm.c && ./alarm  >/tmp/alarm 闹钟chunli@ubuntu:~/linux_c/信号$ tail /tmp/alarmcounter=4763221 counter=4763222 counter=4763223 counter=4763224 counter=4763225 counter=4763226 counter=4763227 counter=4763228 counter=4763229 counter=chunli@ubuntu:~/linux_c/信号$


收到信号的默认操作

Signal     Value     Action   Comment──────────────────────────────────────────────────────────────────────SIGHUP        1       Term    Hangup detected on controlling terminal or death of controlling processSIGINT        2       Term    Interrupt from keyboardSIGQUIT       3       Core    Quit from keyboardSIGILL        4       Core    Illegal InstructionSIGABRT       6       Core    Abort signal from abort(3)SIGFPE        8       Core    Floating point exceptionSIGKILL       9       Term    Kill signalSIGSEGV      11       Core    Invalid memory referenceSIGPIPE      13       Term    Broken pipe: write to pipe with no readersSIGALRM      14       Term    Timer signal from alarm(2)SIGTERM      15       Term    Termination signalSIGUSR1   30,10,16    Term    User-defined signal 1SIGUSR2   31,12,17    Term    User-defined signal 2SIGCHLD   20,17,18    Ign     Child stopped or terminatedSIGCONT   19,18,25    Cont    Continue if stoppedSIGSTOP   17,19,23    Stop    Stop processSIGTSTP   18,20,24    Stop    Stop typed at terminalSIGTTIN   21,21,26    Stop    Terminal input for background processSIGTTOU   22,22,27    Stop    Terminal output for background processThe signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.



信号阻塞 屏蔽<ctrl+c>,<ctrl+z>,<ctrl+\>

Linux系统开发6 信号

chunli@ubuntu:~/linux_c/信号$ cat sigpromask.c #include <stdio.h>#include <unistd.h>#include <signal.h>void printsigset(const sigset_t *set){int i = 0;for(i = 1;i<32;i++){if(sigismember(set,i) == 1){putchar('1');}else{putchar('0');}}puts("");//空行}int main(void){sigset_t s;sigset_t p;//64位系统下有128个字节sigemptyset(&s);//清空信号sigaddset(&s,SIGINT);//添加一个信号,<ctrl+c>sigaddset(&s,SIGTSTP);//添加一个信号,<ctrl+z>sigaddset(&s,SIGQUIT);//添加一个信号,<ctrl+\>sigprocmask(SIG_BLOCK,&s,NULL);//与原来的信号与操作,不要传出数据NULL,当然也可以接受int i = 10;while(i--){sigpending(&p);printsigset(&p);sleep(1);}return 0;}chunli@ubuntu:~/linux_c/信号$ 编译运行,chunli@ubuntu:~/linux_c/信号$ gcc -o sig sigpromask.c && ./sig0000000000000000000000000000000^C0100000000000000000000000000000^\011000000000000000000000000000001100000000000000000000000000000110000000000000000000000000000^Z01100000000000000001000000000000110000000000000000100000000000011000000000000000010000000000001100000000000000001000000000000110000000000000000100000000000chunli@ubuntu:~/linux_c/信号$




解除信号的阻塞

chunli@ubuntu:~/linux_c/信号$ cat sigpromask.c #include <stdio.h>#include <unistd.h>#include <signal.h>void printsigset(const sigset_t *set){int i = 0;for(i = 1;i<32;i++){if(sigismember(set,i) == 1){putchar('1');}else{putchar('0');}}puts("");//空行}int main(void){sigset_t s;sigset_t p;//64位系统下有128个字节sigemptyset(&s);//清空信号sigaddset(&s,SIGINT);//添加一个信号,<ctrl+c>sigaddset(&s,SIGTSTP);//添加一个信号,<ctrl+z>sigaddset(&s,SIGQUIT);//添加一个信号,<ctrl+\>sigprocmask(SIG_BLOCK,&s,NULL);//与原来的信号与操作,不要传出数据NULL,当然也可以接受//完成之后,ctrl+c信号就会被阻塞int i = 0;while(i++ <100){sleep(1);sigpending(&p);//取出信号集信息printsigset(&p);//打印出来if(i == 5){sigdelset(&s,SIGINT);//标记SIGINT信号位删除,相当于置0sigprocmask(SIG_UNBLOCK,&s,NULL);//相当于标记为1的就解除阻塞//那么就只剩 SIGINT 信号是阻塞的了}}return 0;}编译运行:5秒后恢复 crtl+\ 的退出功能chunli@ubuntu:~/linux_c/信号$ gcc -o sig sigpromask.c && ./sig^C^Z0100000000000000000100000000000^\0110000000000000000100000000000011000000000000000010000000000001100000000000000001000000000000110000000000000000100000000000退出 (核心已转储)chunli@ubuntu:~/linux_c/信号$ 但是无论ctrl+c 多少次,都不能终止程序chunli@ubuntu:~/linux_c/信号$ gcc -o sig sigpromask.c && ./sig^C^C0100000000000000000000000000000^C^C0100000000000000000000000000000^C^C^C^C^C01000000000000000000000000000000100000000000000000000000000000^C^C^C^C0100000000000000000000000000000^C^C0100000000000000000000000000000^C^C0100000000000000000000000000000^C^C^C^C^C0100000000000000000000000000000^C010000000000000000000000000000001000000000000000000000000000000100000000000000000000000000000^\退出 (核心已转储)chunli@ubuntu:~/linux_c/信号$



信号捕捉 sa_handler 自定义函数 方式捕捉crtl + c

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c #include <stdio.h>#include <signal.h>#include <unistd.h>//man 2 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 do_sig(int num){printf("\n捕捉到的信号是SIG = %d\n",num);}int main(void){struct sigaction act;act.sa_handler  = do_sig;//结构体函数指针,指向自定义的函数sigemptyset(&act.sa_mask);//清空信号集//act.sa_flags  = 0;sigaction(SIGINT,&act,NULL);//捕捉int i = 1;while(i++){printf("Hello while\n");sleep(1);}return 0;}chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./actionHello whileHello whileHello while^C捕捉到的信号是SIG = 2Hello whileHello while^C捕捉到的信号是SIG = 2Hello while^\退出 (核心已转储)chunli@ubuntu:~/linux_c/信号$



sa_handler 设定为默认 默认处理ctrl+c

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c #include <stdio.h>#include <signal.h>#include <unistd.h>//man 2 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);//};//sa_handler 函数指针//sa_handler specifies the action to be associated with signum and //may be SIG_DFL for the default action, SIG_IGN to ignore this signal, //or a pointer to  a  signal handling function.  //This function receives the signal number as its only argument.void do_sig(int num){printf("\n捕捉到的信号是SIG = %d\n",num);}int main(void){struct sigaction act;//act.sa_handler  = do_sig;//结构体函数指针,指向自定义的函数act.sa_handler  = SIG_DFL;sigemptyset(&act.sa_mask);//清空信号集//act.sa_flags  = 0;sigaction(SIGINT,&act,NULL);//捕捉int i = 1;while(i++){printf("Hello while\n");sleep(1);}return 0;}chunli@ubuntu:~/linux_c/信号$ 编译运行:ctrl+c终止有效果chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./actionHello whileHello whileHello while^C



sa_handler 设定为忽略 ctrl+c

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c #include <stdio.h>#include <signal.h>#include <unistd.h>//man 2 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);//};//sa_handler 函数指针//sa_handler specifies the action to be associated with signum and //may be SIG_DFL for the default action, SIG_IGN to ignore this signal, //or a pointer to  a  signal handling function.  //This function receives the signal number as its only argument.void do_sig(int num){printf("\n捕捉到的信号是SIG = %d\n",num);}int main(void){struct sigaction act;//act.sa_handler  = do_sig;//结构体函数指针,指向自定义的函数//act.sa_handler  = SIG_DFL;act.sa_handler  = SIG_IGN;sigemptyset(&act.sa_mask);//清空信号集//act.sa_flags  = 0;sigaction(SIGINT,&act,NULL);//捕捉int i = 1;while(i++){printf("Hello while\n");sleep(1);}return 0;}编译运行:确实忽略了ctrl+cchunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./actionHello while^C^CHello while^C^C^CHello while^CHello while^CHello while^\退出 (核心已转储)chunli@ubuntu:~/linux_c/信号$


处理信号的时候再来一次信号,并不会嵌套,执行完了再一次执行信号函数

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c #include <stdio.h>#include <signal.h>#include <unistd.h>//man 2 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);//};//sa_handler 函数指针//sa_handler specifies the action to be associated with signum and //may be SIG_DFL for the default action, SIG_IGN to ignore this signal, //or a pointer to  a  signal handling function.  //This function receives the signal number as its only argument.void do_sig(int num){printf("Hello SIG\n");int i = 2;while(i--){sleep(1);printf("\n捕捉到的信号是SIG = %d\n",num);}printf("SIG while end\n");}int main(void){struct sigaction act;act.sa_handler  = do_sig;//结构体函数指针,指向自定义的函数//act.sa_handler  = SIG_DFL;//act.sa_handler  = SIG_IGN;sigemptyset(&act.sa_mask);//清空信号集//act.sa_flags  = 0;sigaction(SIGINT,&act,NULL);//捕捉int i = 1;while(i++){printf("Hello while\n");sleep(1);}return 0;}chunli@ubuntu:~/linux_c/信号$ chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./actionHello while^CHello SIG捕捉到的信号是SIG = 2捕捉到的信号是SIG = 2SIG while endHello while^CHello SIG捕捉到的信号是SIG = 2捕捉到的信号是SIG = 2SIG while endHello SIGHello while^\退出 (核心已转储)chunli@ubuntu:~/linux_c/信号$


sigaddset() 当进入信号函数的调用时屏蔽ctrl+\

退出信号函数的调用后,ctrl+\ 继续默认

1,没有屏蔽 ctrl+\ 信号的时候,执行信号函数会响应ctrl+\操作

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c #include <stdio.h>#include <signal.h>#include <unistd.h>//man 2 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);//};//sa_handler 函数指针//sa_handler specifies the action to be associated with signum and //may be SIG_DFL for the default action, SIG_IGN to ignore this signal, //or a pointer to  a  signal handling function.  //This function receives the signal number as its only argument.void do_sig(int num){printf("Hello SIG\n");int i = 5;while(i--){sleep(1);printf("\n捕捉到的信号是SIG = %d\n",num);}printf("SIG while end\n");}int main(void){struct sigaction act;act.sa_handler  = do_sig;//结构体函数指针,指向自定义的函数//act.sa_handler  = SIG_DFL;//act.sa_handler  = SIG_IGN;sigemptyset(&act.sa_mask);//清空信号集//sigaddset(&act.sa_mask,SIGQUIT);//当进入信号函数的调用时屏蔽ctrl+\act.sa_flags  = 0;sigaction(SIGINT,&act,NULL);//捕捉int i = 1;while(i++){printf("Hello while\n");sleep(1);}return 0;}chunli@ubuntu:~/linux_c/信号$ 编译运行:chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./actionHello while^CHello SIG^\退出 (核心已转储)chunli@ubuntu:~/linux_c/信号$



2,屏蔽 ctrl+\ 信号的时候,执行信号函数不会响应ctrl+\,等运行结束后才会响应

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c #include <stdio.h>#include <signal.h>#include <unistd.h>//man 2 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);//};//sa_handler 函数指针//sa_handler specifies the action to be associated with signum and //may be SIG_DFL for the default action, SIG_IGN to ignore this signal, //or a pointer to  a  signal handling function.  //This function receives the signal number as its only argument.void do_sig(int num){printf("Hello SIG\n");int i = 5;while(i--){sleep(1);printf("\n捕捉到的信号是SIG = %d\n",num);}printf("SIG while end\n");}int main(void){struct sigaction act;act.sa_handler  = do_sig;//结构体函数指针,指向自定义的函数//act.sa_handler  = SIG_DFL;//act.sa_handler  = SIG_IGN;sigemptyset(&act.sa_mask);//清空信号集sigaddset(&act.sa_mask,SIGQUIT);//当进入信号函数的调用时屏蔽ctrl+\act.sa_flags  = 0;sigaction(SIGINT,&act,NULL);//捕捉int i = 1;while(i++){printf("Hello while\n");sleep(1);}return 0;}chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./actionHello whileHello while^CHello SIG^\捕捉到的信号是SIG = 2捕捉到的信号是SIG = 2捕捉到的信号是SIG = 2捕捉到的信号是SIG = 2捕捉到的信号是SIG = 2SIG while end退出 (核心已转储)chunli@ubuntu:~/linux_c/信号$


SIGUSR1用户自定义信号

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c #include <stdio.h>#include <signal.h>#include <unistd.h>//man 2 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);//};//sa_handler 函数指针//sa_handler specifies the action to be associated with signum and //may be SIG_DFL for the default action, SIG_IGN to ignore this signal, //or a pointer to  a  signal handling function.  //This function receives the signal number as its only argument.void do_sig(int num){printf("Hello SIG %d \n",num);}int main(void){struct sigaction act;act.sa_handler  = do_sig;//结构体函数指针,指向自定义的函数act.sa_flags  = 0;sigaction(SIGUSR1,&act,NULL);//捕捉 SIGUSR1自定义信号int i = 1;while(i++){printf("Hello while\n");sleep(1);}return 0;}编译运行:chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action Hello whileHello whileHello SIG 10 Hello whileHello while^C一边发kill信号chunli@ubuntu:~/linux_c/信号$ ps aux | head -n 1 &&  ps aux | tail  -n 4 | head -n 1USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDchunli     8136  0.0  0.0   4356   688 pts/9    S+   15:57   0:00 ./actionchunli@ubuntu:~/linux_c/信号$ kill -SIGUSR1 8136


C 标准库函数,信号捕捉函数

chunli@ubuntu:~/linux_c/信号$ cat sigaction.c #include <stdio.h>#include <signal.h>#include <unistd.h>//C 标准库函数,信号捕捉void do_sig(int n){printf("Hello SIG %d \n",n);}int main(void){signal(SIGINT,do_sig);while(1){printf("well well \n");sleep(1);}return 0;}chunli@ubuntu:~/linux_c/信号$ gcc -o action sigaction.c && ./action well well well well ^CHello SIG 2 well well well well well well ^CHello SIG 2 well well well well ^\退出 (核心已转储)chunli@ubuntu:~/linux_c/信号$





system函数,集成与fork() exit() wait()一体的函数 

chunli@ubuntu:~/linux_c/信号$ cat system.c #include <stdio.h>#include <stdlib.h>int main(int argc,char *argv[]){system("cat /etc/fstab");return 0;}编译运行:chunli@ubuntu:~/linux_c/信号$ gcc system.c && ./a.out# /etc/fstab: static file system information.## Use 'blkid' to print the universally unique identifier for a# device; this may be used with UUID= as a more robust way to name devices# that works even if disks are added and removed. See fstab(5).## <file system> <mount point>   <type>  <options>       <dump>  <pass># / was on /dev/sda1 during installationUUID=59de25c8-6fc2-4346-b1ef-4cbbb3751e53 /               ext4    errors=remount-ro 0       1# swap was on /dev/sda5 during installationUUID=4ac1879d-5732-4436-aeda-39a1ba7adf0c none            swap    sw              0       0chunli@ubuntu:~/linux_c/信号$



可重入 不可重入函数

当在执行函数A时,发生信号处理函数正好也是函数A,如果是不可重入函数,那就受影响


字符串分割,链表插入等默认都是不可重入函数


strtok_r的可重入函数

chunli@ubuntu:~/linux_c/信号$ cat strtok_r.c #include <stdio.h>#include <string.h>int main(void){char str[] = "Hello China Linux guy!";char *save = str;char *p = NULL;while( (p = strtok_r(save," ",&save)) != NULL ){printf("%s \n",p);}return 0;}chunli@ubuntu:~/linux_c/信号$ gcc strtok_r.c && ./a.outHello China Linux guy! chunli@ubuntu:~/linux_c/信号$


Linux下的可重入安全函数

  Async-signal-safe functions       A signal handler function must be very careful, since processing elsewhere may be interrupted at some arbitrary point in the execution of the program.  POSIX has       the  concept of "safe function".  If a signal interrupts the execution of an unsafe function, and handler calls an unsafe function, then the behavior of the pro�\       gram is undefined.       POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2) requires an implementation to guarantee that the  following  functions  can  be  safely  called       inside a signal handler:           _Exit()           _exit()           abort()           accept()           access()           aio_error()           aio_return()           aio_suspend()           alarm()           bind()           cfgetispeed()           cfgetospeed()           cfsetispeed()           cfsetospeed()           chdir()           chmod()           chown()           clock_gettime()           close()           connect()           creat()           dup()           dup2()           execle()           execve()           fchmod()           fchown()           fcntl()           fdatasync()           fork()           fpathconf()           fstat()           fsync()           ftruncate()           getegid()           geteuid()           getgid()           getgroups()           getpeername()           getpgrp()           getpid()           getppid()           getsockname()           getsockopt()           getuid()           kill()           link()           listen()           lseek()           lstat()           mkdir()           mkfifo()           open()           pathconf()           pause()           pipe()           poll()           posix_trace_event()           pselect()           raise()           read()           readlink()           recv()           recvfrom()           recvmsg()           rename()           rmdir()           select()           sem_post()           send()           sendmsg()           sendto()           setgid()           setpgid()           setsid()           setsockopt()           setuid()           shutdown()           sigaction()           sigaddset()           sigdelset()           sigemptyset()           sigfillset()           sigismember()           signal()           sigpause()           sigpending()           sigprocmask()           sigqueue()           sigset()           sigsuspend()           sleep()           sockatmark()           socket()           socketpair()           stat()           symlink()           sysconf()           tcdrain()           tcflow()           tcflush()           tcgetattr()           tcgetpgrp()           tcsendbreak()           tcsetattr()           tcsetpgrp()           time()           timer_getoverrun()           timer_gettime()           timer_settime()           times()           umask()           uname()           unlink()           utime()           wait()           waitpid()           write()       POSIX.1-2008 removes fpathconf(), pathconf(), and sysconf() from the above list, and adds the following functions:           execl()           execv()           faccessat()           fchmodat()           fchownat()           fexecve()           fstatat()           futimens()           linkat()           mkdirat()           mkfifoat()           mknod()           mknodat()           openat()           readlinkat()           renameat()           symlinkat()           unlinkat()           utimensat()           utimes()       POSIX.1-2008 Technical Corrigendum 1 (2013) adds the following functions:           fchdir()           pthread_kill()           pthread_self()           pthread_sigmask()      


pause()系统挂起,等待信号的来临

chunli@ubuntu:~/linux_c/信号$ cat pause.c #include <stdio.h>#include <string.h>#include <signal.h>#include <unistd.h>void do_sig(int n){printf("sig = %d\n",n);}int main(void){struct sigaction act;act.sa_handler = do_sig;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGUSR1,&act,NULL);pause();printf("I'm OK!\n");return 0;}chunli@ubuntu:~/linux_c/信号$ 编译运行:chunli@ubuntu:~/linux_c/信号$ gcc pause.c && ./a.outsig = 10I'm OK!chunli@ubuntu:~/linux_c/信号$ 发送信号:chunli@ubuntu:~/linux_c/信号$ ps aux | head -n 1 &&  ps aux | tail  -n 4 | head -n 1USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDchunli     8522  0.0  0.0   4224   728 pts/9    S+   17:14   0:00 ./a.outchunli@ubuntu:~/linux_c/信号$ kill -SIGUSR1 8522



pause()系统挂起,如果是忽略操作就忽略

chunli@ubuntu:~/linux_c/信号$ cat pause.c #include <stdio.h>#include <string.h>#include <signal.h>#include <unistd.h>void do_sig(int n){printf("sig = %d\n",n);}int main(void){struct sigaction act;//act.sa_handler = do_sig;act.sa_handler = SIG_IGN;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGUSR1,&act,NULL);pause();printf("I'm OK!\n");return 0;}编译运行:chunli@ubuntu:~/linux_c/信号$ gcc pause.c && ./a.out发送信号chunli@ubuntu:~/linux_c/信号$ ps aux | head -n 1 &&  ps aux | tail  -n 4 | head -n 1USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDchunli     8557  0.0  0.0   4224   652 pts/9    S+   17:18   0:00 ./a.outchunli@ubuntu:~/linux_c/信号$ kill -SIGUSR1 8557chunli@ubuntu:~/linux_c/信号$



利用pause() 与 信号 实现my_sleep()函数

#include <stdio.h>#include <string.h>#include <signal.h>#include <unistd.h>#include <time.h>void do_sig(int n){//空函数}void my_sleep(int n){signal(SIGALRM,do_sig);alarm(n);pause();}int main(void){printf("%ld\n",time(NULL));my_sleep(5);printf("%ld\n",time(NULL));return 0;}chunli@ubuntu:~/linux_c/信号$ gcc pause.c && ./a.out14709080431470908048chunli@ubuntu:~/linux_c/信号$




my_sleep()函数 时序竞态问题

执行完alarm(n)函数后,CPU被优先级高的进程夺走

如果n秒内此进程没有被CPU调度,一旦错过alarm信号,将永远挂起了


my_sleep增强 sigsuspend避免了时序竞争 

chunli@ubuntu:~/linux_c/信号$ cat pause.c #include <stdio.h>#include <string.h>#include <signal.h>#include <unistd.h>#include <time.h>void sig_alrm(int n){//do nothing }//sigsuspend避免了时序竞争 sleep增强unsigned int my_sleep(int n){struct sigaction newact;struct sigaction oldact;sigset_t newmask;sigset_t oldmask;sigset_t suspmask;unsigned int unslept;newact.sa_handler = sig_alrm;sigemptyset(&newact.sa_mask);newact.sa_flags = 0;sigaction(SIGALRM,&newact,&oldact);sigemptyset(&newmask);sigaddset(&newmask,SIGALRM);sigprocmask(SIG_BLOCK,&newmask,&oldmask);alarm(n);suspmask = oldmask;sigdelset(&suspmask,SIGALRM);sigsuspend(&suspmask);unslept = alarm(0);sigprocmask(SIG_SETMASK,&oldmask,NULL);return unslept;}int main(void){printf("%ld\n",time(NULL));my_sleep(5);printf("%ld\n",time(NULL));return 0;}chunli@ubuntu:~/linux_c/信号$ gcc pause.c && ./a.out14709113301470911335chunli@ubuntu:~/linux_c/信号$


什么是sig_atomic_t数据类型 


当把变量声明为该类型会保证该变量在使用或赋值时, 

无论是在32位还是64位的机器上都能保证操作是原子的, 它会根据机器的类型自动适应。

这个类型是定义在signal.h文件中。下面来说说这个类型。

在处理信号(signal)的时候,有时对于一些变量的访问希望不会被中断,

无论是硬件中断还是软件中断,这就要求访问或改变这些变量需要在计算机的一条指令内完成。

通常情况下,int类型的变量通常是原子访问的,也可以认为 sig_atomic_t就是int类型的数据,

因为对这些变量要求一条指令完成,所以sig_atomic_t不可能是结构体,只会是数字类型。

chunli@ubuntu:~/linux_c/信号$ uname -rm4.4.0-34-generic x86_64chunli@ubuntu:~/linux_c/信号$ cat long_long.c #include <stdio.h>#include <signal.h>int main(){printf("int = %ld \n",sizeof(int));printf("long = %ld \n",sizeof(long ));printf("long long = %ld \n",sizeof(long long ));printf("double = %ld \n",sizeof(double));printf("char* = %ld \n",sizeof(char *));printf("sig_atomic_t= %ld \n",sizeof(sig_atomic_t));}chunli@ubuntu:~/linux_c/信号$ gcc long_long.c && ./a.out int = 4 long = 8 long long = 8 double = 8 char* = 8 sig_atomic_t= 4 chunli@ubuntu:~/linux_c/信号$


SIGCHLD 信号产生的条件

1 子进程终止时

2 子进程接收到SIGSTOP信号停止时

3 子进程处在停止态,接受到SIGCONT后唤醒时


可以看出[默认是忽略子进程发过来的信号]:

chunli@ubuntu:~$ man 7  signalSignal     Value     Action   Comment──────────────────────────────────────────────────────────────────────SIGHUP        1       Term    Hangup detected on controlling terminal     or death of controlling processSIGINT        2       Term    Interrupt from keyboardSIGQUIT       3       Core    Quit from keyboardSIGILL        4       Core    Illegal InstructionSIGABRT       6       Core    Abort signal from abort(3)SIGFPE        8       Core    Floating point exceptionSIGKILL       9       Term    Kill signalSIGSEGV      11       Core    Invalid memory referenceSIGPIPE      13       Term    Broken pipe: write to pipe with no readersSIGALRM      14       Term    Timer signal from alarm(2)SIGTERM      15       Term    Termination signalSIGUSR1   30,10,16    Term    User-defined signal 1SIGUSR2   31,12,17    Term    User-defined signal 2SIGCHLD   20,17,18    Ign     Child stopped or terminatedSIGCONT   19,18,25    Cont    Continue if stoppedSIGSTOP   17,19,23    Stop    Stop processSIGTSTP   18,20,24    Stop    Stop typed at terminalSIGTTIN   21,21,26    Stop    Terminal input for background process


用信号回收子进程

chunli@ubuntu:~/linux_c/信号$ cat child.c #include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <sys/types.h>#include <sys/wait.h>#include <signal.h>void sys_err(char *str){perror(str);exit(1);}void do_sig_child(int signo){int status;pid_t pid;while ((pid = waitpid(0, &status, WNOHANG)) > 0) {if (WIFEXITED(status))printf("child %d exit %d\n", pid, WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("child %d cancel signal %d\n", pid, WTERMSIG(status));}}int main(void){pid_t pid;int i;//阻塞SIGCHLDfor (i = 0; i < 10; i++) {if ((pid = fork()) == 0)break;else if (pid < 0)sys_err("fork");}if (pid == 0) {int n = 5;while (n--) {printf("child ID %d\n", getpid());sleep(1);}return i;//每个子进程的i是不一样的}else if (pid > 0) {//先设置捕捉//再解除对SIGCHLD的阻塞struct sigaction act;act.sa_handler = do_sig_child;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGCHLD, &act, NULL);int n = 10;while (n--) {printf("Parent ID %d\n", getpid());sleep(1);}}return 0;}1,正常编译运行:chunli@ubuntu:~/linux_c/信号$ gcc child.c && ./a.out child ID 5413child ID 5414child ID 5415child ID 5418child ID 5422child ID 5421child ID 5420child ID 5419Parent ID 5412child ID 5416child ID 5417child ID 5413child ID 5415child ID 5414Parent ID 5412child ID 5417child ID 5416child ID 5421child ID 5420child ID 5418child ID 5419child ID 5422child ID 5415child ID 5413child ID 5414child ID 5417child ID 5416child ID 5421child ID 5420child ID 5419child ID 5418child ID 5422Parent ID 5412child ID 5415child ID 5422child ID 5421child ID 5420child ID 5419child ID 5418Parent ID 5412child ID 5416child ID 5417child ID 5413child ID 5414child ID 5422child ID 5421child ID 5420child ID 5418child ID 5419Parent ID 5412child ID 5416child ID 5417child ID 5415child ID 5413child ID 5414child 5415 exit 2child 5416 exit 3child 5418 exit 5child 5419 exit 6child 5420 exit 7child 5417 exit 4child 5421 exit 8child 5422 exit 9Parent ID 5412child 5413 exit 0Parent ID 5412child 5414 exit 1Parent ID 5412Parent ID 5412Parent ID 5412chunli@ubuntu:~/linux_c/信号$ 2,手动kill子进程,编译运行:chunli@ubuntu:~/linux_c/信号$ gcc child.c && ./a.out child ID 5664child ID 5666child ID 5667child ID 5668child ID 5669Parent ID 5663child ID 5671child ID 5672child ID 5673child ID 5670child ID 5665child ID 5664child ID 5666child ID 5668child ID 5667child ID 5669Parent ID 5663child ID 5670child ID 5672child ID 5673child ID 5671child ID 5665child 5673 cancel signal 9Parent ID 5663child ID 5664child ID 5666child ID 5667child ID 5668child ID 5669child ID 5672child ID 5671child ID 5670child ID 5665child 5672 cancel signal 9Parent ID 5663child 5671 cancel signal 9Parent ID 5663child ID 5664child ID 5666child ID 5668child ID 5669child ID 5667child ID 5665child ID 5670child 5669 cancel signal 9Parent ID 5663child 5670 cancel signal 9Parent ID 5663child 5668 cancel signal 9Parent ID 5663child ID 5664child ID 5666child ID 5667child ID 5665child 5667 cancel signal 9Parent ID 5663child 5664 exit 0Parent ID 5663child 5665 exit 1child 5666 exit 2chunli@ubuntu:~/linux_c/信号$ chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`chunli@ubuntu:~$ kill -9 `ps aux| grep a.out | awk '{print $2}'|tail -n 2|head -n 1`-bash: kill: (5718) - 没有那个进程chunli@ubuntu:~$


Linux系统开发6 信号



作业:

1.当进程处理SIGINT信号时,临时阻塞SIGQUIT信号。 2.进程间利用信号传参,来控制

数据同步,如两个进程交叉报数。







本文出自 “李春利” 博客,谢绝转载!