【本文谢绝转载,原文来自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+\>
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:~$
作业:
1.当进程处理SIGINT信号时,临时阻塞SIGQUIT信号。 2.进程间利用信号传参,来控制
数据同步,如两个进程交叉报数。
本文出自 “李春利” 博客,谢绝转载!