赞
踩
信号:
信号机制是类UNIX系统中的一种重要的进程间通信手段之一。我们经常使用信号来向一个进程发送一个简短的消息。例如:假设我们启动一个进程通过socket读取远程主机发送过来的网络数据包,此时由于网络因素当前主机还没有收到相应的数据,当前进程被设置为可中断等待状态(TASK_INTERRUPTIBLE),此时我们已经失去耐心,想提前结束这个进程,于是可以通过kill命令想这个进程发送KILL信号,内核会唤醒该进程,执行它的信号处理函数,KILL信号的默认处理是退出该进程。
另外应用程序可以通过signal()等函数来为一个信号设置默认处理函数。例如当用户按下CTRL+C时,shell将会发出SIGINT信号,SIGINT的默认处理函数是执行进程的退出代码,如下所示:
可以通过类似下面的命令显式的给一个进程发送一个信号:
kill -2 pid事实上,进程也不知道信号到底什么时候到达。信号是异步的,一个进程不可能等待信号的到来,也不知道信号会到来,那么,进程是如何发现和接受信号呢?实际上,信号的接收不是由用户进程来完成的,而是由内核代理。当一个进程P2向另一个进程P1发送信号后,内核接受到信号,并将其放在P1的信号队列当中。当P1再次陷入内核态时,会检查信号队列,并根据相应的信号调取相应的信号处理函数。
信号检测和响应时机
刚才我们说,当P1再次陷入内核时,会检查信号队列。那么,P1什么时候会再次陷入内核呢?陷入内核后在什么时机会检测信号队列呢?
进入信号处理函数
发现信号后,根据信号向量,知道了处理函数,那么该如何进入信号处理程序,又该如何返回呢?
我们知道,用户进程提供的信号处理函数是在用户态里的,而我们发现信号,找到信号处理函数的时刻处于内核态中,所以我们需要从内核态跑到用户态去执行信号处理程序,执行完毕后还要返回内核态。
- #include <signal.h>
- #include <stdio.h>
-
- void int_handler(int signum)
- {
- printf("\nSIGINT signal handler.\n");
- printf("exit.\n");
- exit(-1);
- }
-
- int main()
- {
- signal(SIGINT, int_handler);
- printf("int_handler set for SIGINT\n");
-
- while(1)
- {
- printf("go to sleep.\n");
- sleep(60);
- }
-
- return 0;
- }
信号量:
一.什么是信号量二.信号量的分类
(1)有名信号量,其值保存在文件中,所以它既可以用于线程,也可以用于相关进程间,甚至是不相关进程。
(2)无名信号量,其值保存在内存中。无名信号量常用于多线程间的同步,同时也用于相关进程间的同步。也就是说,无名信号量必须是多个进程(线程)的共享变量,无名信号量要保护的变量也必须是多个进程(线程)的共享变量,这两个条件是缺一不可的。
倘若对信号量没有以上的全面认识的话,你就会很快发现自己在信号量的森林里迷失了方向。
POSIX 信号量与SYSTEM V信号量的比较:
1. 对POSIX来说,信号量是个非负整数。常用于线程间同步。而SYSTEM V信号量则是一个或多个信号量的集合,它对应的是一个信号量结构体,这个结构体是为SYSTEM V IPC服务的,信号量只不过是它的一部分。常用于进程间同步。
2.POSIX信号量的引用头文件是“<semaphore.h>”,而SYSTEM V信号量的引用头文件是“<sys/sem.h>”。
3.从使用的角度,System V信号量是复杂的,而Posix信号量是简单。比如,POSIX信号量的创建和初始化或PV操作就很非常方便。
无名信号量:
- #include <pthread.h>
- #include <semaphore.h>
- #include <sys/types.h>
- #include <stdio.h>
- #include <unistd.h>
- int number; // 被保护的全局变量
- sem_t sem_id;
- void* thread_one_fun(void *arg)
- {
- sem_wait(&sem_id);
- printf("thread_one have the semaphore\n");
- number++;
- printf("number = %d\n",number);
- sem_post(&sem_id);
- }
- void* thread_two_fun(void *arg)
- {
- sem_wait(&sem_id);
- printf("thread_two have the semaphore \n");
- number--;
- printf("number = %d\n",number);
- sem_post(&sem_id);
- }
- int main(int argc,char *argv[])
- {
- number = 1;
- pthread_t id1, id2;
- sem_init(&sem_id, 0, 1);
- pthread_create(&id1,NULL,thread_one_fun, NULL);
- pthread_create(&id2,NULL,thread_two_fun, NULL);
- pthread_join(id1,NULL);
- pthread_join(id2,NULL);
- printf("main,,,\n");
- return 0;
- }
- //File1: server.c </u>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <stdio.h>
- #include <semaphore.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #define SHMSZ 27
- char SEM_NAME[]= "vik";
- int main()
- {
- char ch;
- int shmid;
- key_t key;
- char *shm,*s;
- sem_t *mutex;
- //name the shared memory segment
- key = 1000;
- //create & initialize semaphore
- mutex = sem_open(SEM_NAME,O_CREAT,0644,1);
- if(mutex == SEM_FAILED)
- {
- perror("unable to create semaphore");
- sem_unlink(SEM_NAME);
- exit(-1);
- }
- //create the shared memory segment with this key
- shmid = shmget(key,SHMSZ,IPC_CREAT|0666);
- if(shmid<0)
- {
- perror("failure in shmget");
- exit(-1);
- }
- //attach this segment to virtual memory
- shm = shmat(shmid,NULL,0);
- //start writing into memory
- s = shm;
- for(ch='A';ch<='Z';ch++)
- {
- sem_wait(mutex);
- *s++ = ch;
- sem_post(mutex);
- }
- //the below loop could be replaced by binary semaphore
- while(*shm != '*')
- {
- sleep(1);
- }
- sem_close(mutex);
- sem_unlink(SEM_NAME);
- shmctl(shmid, IPC_RMID, 0);
- exit(0);
- }
- //File 2: client.c</u>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <stdio.h>
- #include <semaphore.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #define SHMSZ 27
- char SEM_NAME[]= "vik";
- int main()
- {
- char ch;
- int shmid;
- key_t key;
- char *shm,*s;
- sem_t *mutex;
- //name the shared memory segment
- key = 1000;
- //create & initialize existing semaphore
- mutex = sem_open(SEM_NAME,0,0644,0);
- if(mutex == SEM_FAILED)
- {
- perror("reader:unable to execute semaphore");
- sem_close(mutex);
- exit(-1);
- }
- //create the shared memory segment with this key
- shmid = shmget(key,SHMSZ,0666);
- if(shmid<0)
- {
- perror("reader:failure in shmget");
- exit(-1);
- }
- //attach this segment to virtual memory
- shm = shmat(shmid,NULL,0);
- //start reading
- s = shm;
- for(s=shm;*s!=NULL;s++)
- {
- sem_wait(mutex);
- putchar(*s);
- sem_post(mutex);
- }
- //once done signal exiting of reader:This can be replaced by
- another semaphore
- *shm = '*';
- sem_close(mutex);
- shmctl(shmid, IPC_RMID, 0);
- exit(0);
- }
System V信号量:
- int sem_id = 0; /* semget的返回值,全局 */
- #define MUTEX 0 /* 用于返回临界区的信号量在集合中的序数 */
- #define NUM_SEM 1 /* 集合中信号量的个数 */
- #define SEM_KEY 0x11223344 /*保证内核中的唯一性 */
-
- void P(int sem_num)
- {
- struct sembuf sem;
- sem.sem_num = MUTEX;
- sem.sem_op = -1;
- sem.sem_flg = 0;
-
- if( -1 == semop(sem_id, &sem, 1) )
- {
- /* 错误处理 */
- }
- }
-
-
- void V(int sem_num)
- {
- struct sembuf sem;
- sem.sem_num = MUTEX;
- sem.sem_op = 1;
- sem.sem_flg = 0;
-
- if( -1 == semop(sem_id, &sem, 1) )
- {
- /* 错误处理 */
- }
- }
-
- 主函数:
-
- int main()
- {
- ...
- int semid;
- ....
- semid = semget(SEM_KEY, 0, 0); /* panduan 判断该型号量组是否已经存在 */
- if( -1 == semid )
- {
- semid = semget(SEM_KEY, NUM_SEM, IPC_CREAT | IPC_EXCL | 0666);
- if( -1 == semid)
- {
- /* 错误处理 */
- }
- else
- {
- semctl(sem_id, MUTEX, SETVAL, 1); /* 初始值为1。错误处理略 */
- }
- }
-
- ...
- P(MUTEX);
- /* 临界区代码段 */
- V(MUTEX);
- ...
- }
最全面的linux信号量解析:http://blog.csdn.net/qinxiongxu/article/details/7830537
信号只是一个数字,数字为0-31表示不同的信号,如下表所示。
编号 | 信号名 | 默认动作 | 说明 |
1 | SIGHUP | 进程终止 | 终端断开连接 |
2 | SIGINT | 进程终止 | 用户在键盘上按下CTRL+C |
3 | SIGQUIT | 进程意外结束(Dump) | 用户在键盘上按下CTRL+\ |
4 | SIGILL | 进程意外结束(Dump) | 遇到非法指令 |
5 | SIGTRAP | 进程意外结束(Dump) | 遇到断电,用于调试 |
6 | SIGABRT/SIGIOT | 进程意外结束(Dump) | |
7 | SIGBUS | 进程意外结束(Dump) | 总线错误 |
8 | SIGFPE | 进程意外结束(Dump) | 浮点异常 |
9 | SIGKILL | 进程终止 | 其他进程发送SIGKILL将导致目标进程终止 |
10 | SIGUSR1 | 进程终止 | 应用程序可自定义使用 |
11 | SIGSEGV | 进程意外结束(Dump) | 非法的内存访问 |
12 | SIGUSR2 | 进程终止 | 应用程序可自定义使用 |
13 | SIGPIPE | 进程终止 | 管道读取端已经关闭,写入端进程会收到该信号 |
14 | SIGALRM | 进程终止 | 定时器到时 |
15 | SIGTERM | 进程终止 | 发送该信号使目标进程终止 |
16 | SIGSTKFLT | 进程终止 | 堆线错误 |
17 | SIGCHLD | 忽略 | 子进程退出时会向父进程发送该信号 |
18 | SIGCONT | 忽略 | 进程继续执行 |
19 | SIGSTOP | 进程暂停 | 发送该信号会使目标进程进入TASK_STOPPED状态 |
20 | SIGTSTP | 进程暂停 | 在终端上按下CTRL+Z |
21 | SIGTTIN | 进程暂停 | 后台进程从控制终端读取数据 |
22 | SIGTTOU | 进程暂停 | 后台进程从控制终端读取数据 |
23 | SIGURG | 忽略 | socket收到设置紧急指针标志的网络数据包 |
24 | SIGXCPU | 进程意外结束(Dump) | 进程使用CPU已经超过限制 |
25 | SIGXFSZ | 进程意外结束(Dump) | 进程使用CPU已经超过限制 |
26 | SIGVTALRM | 进程终止 | 进程虚拟定时器到期 |
27 | SIGPROF | 进程终止 | 进程Profile定时器到期 |
28 | SIGMNCH | 忽略 | 进程终端窗口大小改变 |
29 | SIGIO | 进程暂停 | 用于异步IO |
29 | SIGPOLL | 进程暂停 | 用于异步IO |
30 | SIGPWR | 进程暂停 | 电源失效 |
31 | SIGUNUSED | 进程暂停 | 保留未使用 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。