信号
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
int kill(pid_t pid, int sig);
- 利用指令kill -l 可以查看所有信号,其中信号2是我们常用的ctrl+c,信号9为杀死进程此信号不可转换和忽略,SIG_IGN为无视信号的宏,而信号9不可被无视
- signum为信号写数字也行写名称也行,handler为函数指针将其信号的处理转化为handler指向的服务函数
DEMO
#include <signal.h>
#include "stdio.h"
int main(int argc,char **argv)
{
int signum;
int pid;
char cmd[128]={0};
signum=atoi(argv[1]);
pid = atoi(argv[2]);
printf("num=%d,pid=%d\n",signum,pid);
// kill(pid,signum);
sprintf(cmd,"kill -%d %d",signum,pid);
system(cmd);
printf("send signal ok\n")
return 0;
}
void handler(int signum)
{
printf("get signum=%d\n",signum);
switch(signum){
case 2:
printf("SIGINT\n");
break;
case 9:
printf("SIGKILL\n");
break;
case 10:
printf("SIGUSR1\n");
break;
}
printf("never quit\n");
}
int main()
{
signal(SIGINT,SIG_IGN); //无视信号的宏
signal(SIGKILL,handler);
signal(SIGUSR1,handler);
while(1); //等待信号接受,不让进程退出
return 0;
}
信号带消息
int sigqueue(pid_t pid, int sig, const union sigval value);
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
- sigqueue函数参数一为发送进程的pid,参数而为发送的信号,参数三为携带的数据如以下的共用体
union sigval_t {
int sival_int;
void *sival_ptr;
};
- sigaction函数中参数一为接受的信号,参数二是一个已定义的结构体指针形参,结构体struct sigaction
- 参数三oldact参数输出先前信号的处理方式(如果不为NULL的话)
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
} //其中变量一为信号转换函数,如果设置了相当于signal函数差不多,设置了sigaction函数指针相当于携带消息的服务函数,sa_mask默认表示阻塞这里不设置表示以默认设置,sa_flags一般设置为SA_SIGINFO表示有消息
-
SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用 SA_NODEFER :一般情况下,当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号 -
如果设置sa_sigaction指针变量,其处理函数有三个形参,第一个形参为接受的信号,第二个为接受消息的结构体指针,第三个形参当其不为NULL表示有消息
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since kernel 2.6.32) */
}
DEMO
#include <signal.h>
#include "stdio.h"
// int sigaction(int signum, const struct sigaction *act,
// struct sigaction *oldact);
void handler(int signum, siginfo_t *info, void *context)
{
printf("get signum %d\n",signum);
if(context!=NULL){
printf("get data=%d\n",info->si_int);
// printf("get str=%s\n",(char *)info->si_value.sival_ptr);
printf("get data=%d\n",info->si_value.sival_int);
printf("from pid=%d\n",info->si_pid);
}
}
int main()
{
struct sigaction act;
printf("pid = %d\n",getpid());
act.sa_sigaction=handler; //带消息的函数
act.sa_flags=SA_SIGINFO; //表示有消息
sigaction(SIGUSR1,&act,NULL); //SIGUSR1为信号10的宏
while(1);
return 0;
}
int main(int argc,char **argv)
{
int signum;
int pid;
signum=atoi(argv[1]);
pid=atoi(argv[2]);
union sigval value;
// value.sival_ptr="xiaoma";
value.sival_int=100;
sigqueue(pid,signum,value);
printf("%d,done\n",getpid());
return 0;
}
信号量
1 #include <sys/sem.h>
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf *sops, unsigned nsops);
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);
- semget函数第二参数为必须指定集合中信号量的个数(即num_sems),通常为1, 如果是引用一个现有的集合,则将num_sems指定为 0 。函数第三个参数如果没有就利用IPC_CREAT创建并赋予权限
- semop函数第二个参数指向一个结构体结构体参数如下,sem_num为第几个信号量,像数组标号一下,写0为第一个,对于第二个sem_op一次操作中的信号量的改变量;第三个参数nsops 这个是每次操作的工作(struct sembuf)数量,由于我们操作一个因此写1
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
- 若sem_op > 0,表示进程释放相应的资源数,将 sem_op 的值加到信号量的值上。如果有进程正在休眠等待此信号量,则换行它们。 若sem_op < 0,请求 sem_op 的绝对值的资源。
如果相应的资源数可以满足请求,则将该信号量的值减去sem_op的绝对值,函数成功返回。
当相应的资源数不能满足请求时,这个操作与sem_flg有关。 sem_flg
指定IPC_NOWAIT,则semop函数出错返回EAGAIN。 sem_flg
没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生:
当相应的资源数可以满足请求,此信号量的semncnt值减1,该信号量的值减去sem_op的绝对值。成功返回;
此信号量被删除,函数smeop出错返回EIDRM;
进程捕捉到信号,并从信号处理函数返回,此情况下将此信号量的semncnt值减1,函数semop出错返回EINTR 若sem_op ==
0,进程阻塞直到信号量的相应值为0: 当信号量已经为0,函数立即返回。 如果信号量的值不为0,则依据sem_flg决定函数动作:
sem_flg指定IPC_NOWAIT,则出错返回EAGAIN。
sem_flg没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生:
信号量值为0,将信号量的semzcnt的值减1,函数semop成功返回; 此信号量被删除,函数smeop出错返回EIDRM;
进程捕捉到信号,并从信号处理函数返回,在此情况将此信号量的semncnt值减1,函数semop出错返回EINTR
一般指定sem_flg为SEM_UNDO - 对于semctl函数,其中第一而参数为第几个信号量,写0代表第一个信号量,对于第三个参数cmd一般指定为SETVAL设定初值,第三个参数为一个结构体,在man手册中需要我们去定义这个结构体
- SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。
- IPC_RMID:删除一个信号量集合。如果不删除信号量,它将继续在系统中存在,即使程序已经退出,它可能在你下次运行此程序时引发问题,而且信号量是一种有限的资源。
DEMO
#include "stdio.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
// int semget(key_t key, int nsems, int semflg);
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
// int semop(int semid, struct sembuf *sops, unsigned nsops);
void pGetKey(int id)
{
struct sembuf set;
set.sem_num=0; //信号量的编号
set.sem_op=-1;
set.sem_flg=SEM_UNDO; //锁住或者解锁
semop(id,&set,1);
printf("get key\n");
}
void vPutBackKey(int id)
{
struct sembuf set;
set.sem_num=0;
set.sem_op=1;
set.sem_flg=SEM_UNDO;
semop(id,&set,1);
printf("put back the key\n");
}
int main()
{
key_t key;
int semid;
key=ftok(".",2);
//信号量集合中有一个信号量
semid=semget(key,1,IPC_CREAT|0666);//获取/创建信号量
union semun initsem;
initsem.val = 0;
//控制第0个信号量
semctl(semid,0,SETVAL,initsem);//初始信号量的值
//SETVAL设置信号量的值 设置为inisem
int pid=fork();
if(pid>0){
pGetKey(semid);
printf("this is father\n");
vPutBackKey(semid);
semctl(semid,0,IPC_RMID);
}else if(pid==0){
printf("this is child\n");
vPutBackKey(semid);
}else{
printf("fork error\n");
}
return 0;
}
**
- 先将信号量初值设置为0,到子进程去把钥匙释放位置前,父进程都拿不到钥匙,因此执行结果为
this is son
put the key
get the key
this is father
put the key