系统编程函数之信号量

时间:2021-04-05 14:42:43
1、kill NAME        kill - send signal to a process SYNOPSIS        #include <sys/types.h>        #include <signal.h>        int kill(pid_t pid, int sig); RETURN VALUE        On success (at least one signal was sent), zero is returned.  On error, -1 is returned, and errno is set appropriately. 使用: int main(int argc, char *argv[]) {     int i = 0;     pid_t pid = atoi(argv[1]);     while (1)     {         printf("this is %dth while\n", i+1);         sleep(1);         i++;         if (5 == i)         {             printf("kill other process\n");             kill(pid, SIGKILL);         }     }     return 0; }

2、raise 发送一个信号给进程本身(完全可以用kill代替) NAME        raise - send a signal to the caller SYNOPSIS        #include <signal.h>        int raise(int sig);

3、alarm 定时发送信号 ,结束程序 //SIGALRM 不可以设多个,后面的会替代前面的 NAME        alarm - set an alarm clock for delivery of a signal SYNOPSIS        #include <unistd.h>        unsigned int alarm(unsigned int seconds); RETURN VALUE        alarm()  returns the number of seconds remaining until any previously scheduled alarm was due to be delivered, or zero if there was        no previously scheduled alarm. 使用: int main(void) {     alarm(5); //SIGALRM:结束程序     alarm(2); //会将之前的闹钟取消
    while (1)     {         printf("aaaaaaa\n");         sleep(1);     }     return 0; }


1、设置信号处理动作:singalNAME       signal - ANSI C signal handlingSYNOPSIS       #include <signal.h>       typedef void (*sighandler_t)(int);       sighandler_tsignal(int signum, sighandler_t handler);RETURN VALUE       signal() returns the previous value of the signal handler, or SIG_ERR on error.  In the event of an error, errno is set to indicate       the cause.使用:void handle(int sig){    if (SIGINT == sig)    {        printf("catched sigint\n");    }}int main(void){    //ctrl+c: SIGINT    //设置信号的处理动作    signal(SIGINT, handle);    while (1)    {        printf("this is main while\n");        sleep(1);    }    return 0;}

2、屏蔽信号(1)将信号添加到信号组: sigemptyset sigaddset NAMEdfsigemptyset, sigfillset, sigaddset, sigdelset, sigismember - POSIX signal set operationsSYNOPSIS       #include <signal.h>       int sigemptyset(sigset_t *set);  //清空信号集合       int sigfillset(sigset_t *set);       int sigaddset(sigset_t *set, int signum);  //添加信号到集合中       int sigdelset(sigset_t *set, int signum);       int sigismember(const sigset_t *set, int signum);DESCRIPTION       These functions allow the manipulation of POSIX signal sets.       sigemptyset() initializes the signal set given by set to empty, with all signals excluded from the set.       sigfillset() initializes set to full, including all signals.       sigaddset() and sigdelset() add and delete respectively signal signum from set.       sigismember() tests whether signum is a member of set.       Objects of type sigset_t must be initialized by a call to either sigemptyset() or sigfillset() before being passed to the functions       sigaddset(), sigdelset() and sigismember() or the additional glibc functions described  below  (sigisemptyset(),  sigandset(),  and       sigorset()).  The results are undefined if this is not done.RETURN VALUE       sigemptyset(), sigfillset(), sigaddset(), and sigdelset() return 0 on success and -1 on error.       sigismember() returns 1 if signum is a member of set, 0 if signum is not a member, and -1 on error.       On error, these functions set errno to indicate the cause of the error.(2)对信号组进行设置:sigprocmaskNAME       sigprocmask, rt_sigprocmask - examine and change blocked signalsSYNOPSIS       #include <signal.h>    参数2:sigset_t 结构体,信号集合, 将需要的信号添加到其中即可       int sigprocmask(int how,const sigset_t *set, sigset_t *oldset);   参数3:信号之前的状态SIG_BLOCK  (阻塞) 也就是上面的参数1:how              The set of blocked signals is the union of the current set and the set argument.       SIG_UNBLOCK (解阻塞)              The signals in set are removed from the current set of blocked signals.  It is permissible to attempt to  unblock  a  signal              which is not blocked.       SIG_SETMASK              The set of blocked signals is set to the argument set.RETURN VALUE       sigprocmask() returns 0 on success and -1 on error.  In the event of an error, errno is set to indicate the cause.使用:sigset_t set;void handle(int sig){    //ctrl+c    if (SIGINT == sig)    {#if 0        //若信号阻塞的操作是在信号的处理函数中进行的        //则函数结束后,阻塞无效        sigset_t set;        //清空信号集合        sigemptyset(&set);        //添加SIGTSTP到集合中        sigaddset(&set, SIGTSTP);        //SIG_BLOCK:将信号集合中的信号阻塞        //参数三:用来保存参数二中的信号之前的状态        //NULL表示不保存之前的状态        sigprocmask(SIG_BLOCK, &set, NULL);#endif        printf("$$$$$$$$$$$$$$$$\n");        int i = 0;        while (1)        {            printf("this is SIGINT handle\n");            sleep(1);            i++;            if (5 == i)            {                break;            }        }        //若有一个信号被阻塞但是多次发生        //则解阻塞之后该信号只会被处理一次        sigprocmask(SIG_UNBLOCK, &set, NULL);    }    else if (SIGTSTP == sig)    {        //ctrl+z        printf("this is SIGTSTP handle\n");    }}
int main(void){   //    sigset_t set;    //清空信号集合    sigemptyset(&set);    //添加SIGTSTP到集合中    sigaddset(&set, SIGTSTP);    //SIG_BLOCK:将信号集合中的信号阻塞    //参数三:用来保存参数二中的信号之前的状态    //NULL表示不保存之前的状态    sigprocmask(SIG_BLOCK, &set, NULL);    signal(SIGINT, handle);       signal(SIGTSTP, handle);       while (1)    {        printf("this is main while \n");        sleep(1);    }    return 0;}


3、一个函数完成上面上面两个功能:sigactionNAME       sigaction, rt_sigaction - examine and change a signal actionSYNOPSIS       #include <signal.h>       int sigaction(int signum,const struct sigaction *act,       参数1:要处理的信号 参数2:通过结构体对信号进行                    struct sigaction *oldact);                                      参数3:保留之前的处理方式,不想保留设置为: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);           };           SA_NOCLDSTOP  flags: 若信号是SIGCHLD,处理过程中不处理其他信号                  If  signum  is  SIGCHLD,  do not receive notification when child processes stop (i.e., when they receive one of SIGSTOP,                  SIGTSTP, SIGTTIN, or SIGTTOU) or resume (i.e., they receive SIGCONT) (see wait(2)).  This flag is meaningful  only  when                  establishing a handler for SIGCHLD.           SA_NOCLDWAIT (since Linux 2.6)                  If  signum  is  SIGCHLD, do not transform children into zombies when they terminate.  See also waitpid(2).  This flag is                  meaningful only when establishing a handler for SIGCHLD, or when setting that signal's disposition to SIG_DFL.                  If the SA_NOCLDWAIT flag is set when establishing a handler for SIGCHLD, POSIX.1 leaves it unspecified whether a SIGCHLD                  signal  is  generated  when  a  child process terminates.  On Linux, a SIGCHLD signal is generated in this case; on some                  other implementations, it is not.           SA_NODEFER  //处理A A再次发生 不阻塞A                  Do not prevent the signal from being received from within its own signal handler.  This flag  is  meaningful  only  when                  establishing a signal handler.  SA_NOMASK is an obsolete, nonstandard synonym for this flag.           SA_ONSTACK                    Call  the  signal  handler on an alternate signal stack provided by sigaltstack(2).  If an alternate stack is not avail‐                 able, the default stack will be used.  This flag is meaningful only when establishing a signal handler.           SA_RESETHAND  //当信号发生时调用特殊函数处理,处理完按默认方式处理,仅执行一次                  Restore the signal action to the default upon entry to the signal handler.  This flag is meaningful only when establish‐                  ing a signal handler.  SA_ONESHOT is an obsolete, nonstandard synonym for this flag.           SA_RESTART                  Provide  behavior  compatible with BSD signal semantics by making certain system calls restartable across signals.  This                  flag is meaningful only when establishing a signal handler.  See signal(7) for a discussion of system call restarting.           SA_RESTORER                  Not intended for application use.  This flag is used by C libraries to indicate that the sa_restorer field contains  the                 address of a "signal trampoline".  See sigreturn(2) for more details.           SA_SIGINFO (since Linux 2.2)                  The  signal  handler  takes  three  arguments, not one.  In this case, sa_sigaction should be set instead of sa_handler.                  This flag is meaningful only when establishing a signal handler.RETURN VALUE       sigaction() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.使用:void handle(int sig){    if (SIGINT == sig)    {        printf("$$$$$$$$$$$$$$$$\n");        int i = 0;        while (1)        {            printf("this is SIGINT handle\n");            sleep(1);            i++;            if (5 == i)            {                break;            }        }    }    else if (SIGTSTP == sig)    {        //ctrl+z        printf("this is SIGTSTP handle\n");    }}int main(void){       struct sigaction act;    act.sa_handler = handle;    sigemptyset(&(act.sa_mask));    sigaddset(&(act.sa_mask), SIGTSTP);    //通过结构体同时设置某个信号的处理函数和需要屏蔽的信号集    sigaction(SIGINT, &act, NULL);    struct sigaction act2;    act2.sa_handler = handle;    sigaction(SIGTSTP, &act2, NULL);    while (1)    {        printf("this is main while \n");        sleep(1);    }    return 0;}



1、信号的创建:sem_init   (一般用于线程同步)    NAME       sem_init - initialize an unnamed semaphoreSYNOPSIS       #include <semaphore.h>参数1:要初始化的信号量 2:设置该信号量用于       int sem_init(sem_t *sem,int pshared,unsigned int value);  //初始化信号量  参数1:要初始化的信号量                                                                                                           Link with -pthread.                                                    //参数2:设置该信号量用于进程间同步还是用于线程间同步  //0:表示用于线程间  //非0:表示用于进程间RETURN VALUE                                                              //参数3:信号量的整数值,代表资源的可用数       sem_init() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.
2、信号的等待:sem_waitNAME       sem_wait, sem_timedwait, sem_trywait - lock a semaphoreSYNOPSIS       #include <semaphore.h>       int sem_wait(sem_t *sem);  //等于0等待       int sem_trywait(sem_t *sem);   //等于0不等待,去做其他事       int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); //等于0,等待指定之间,然后去做其他事
3、通知等待某信号的线程:sem_post  将信号量加1NAME       sem_post - unlock a semaphoreSYNOPSIS       #include <semaphore.h>       int sem_post(sem_t *sem);       Link with -pthread.RETURN VALUE       sem_post() returns 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno is set to  indi‐       cate the error.

1、信号量的创建semget    //创建信号量集合    //参数一:使用一个十六进制的整数作为该集合的名字    //        名字可以重复    //参数二: 设置该集合中信号量的个数    //IPC_CREAT|0664:创建集合并指定操作权限    //成功返回该集合的标识符,    //通过标识符来唯一确定集合    semid = semget(0x1024, NUM, IPC_CREAT|0664);

2、对信号量的设定semop1)创建信号集 semid = semget。。semid = semget(0x1024, NUM, IPC_CREAT|0664);2)定义结构体 struct sembuf sem    int left = num;    int right = (num+1)%NUM;    struct sembuf sem[2] = {{left, -1, 0}                            , {right, -1, 0}};3)//通过结构体指定的操作来操作集合中的信号量semop(semid, sem, 2);参数1:信号集标识符,参数2:
sops:指向进行操作的信号量集结构体数组的首地址,此结构的具体说明如下:struct sembuf {    short semnum; /*信号量集合中的信号量编号,0代表第1个信号量*/    short val;/*若val>0进行V操作信号量值加val,表示进程释放控制的资源 *//*若val<0进行P操作信号量值减val,若(semval-val)<0(semval为该信号量值),则调用进程阻塞,直到资源可用;若设置IPC_NOWAIT不会睡眠,进程直接返回EAGAIN错误*/  /*若val==0时阻塞等待信号量为0,调用进程进入睡眠状态,直到信号值为0;若设置IPC_NOWAIT,进程不会睡眠,直接返回EAGAIN错误*/    short flag;  /*0 设置信号量的默认操作*//*IPC_NOWAIT设置信号量操作不等待*//*SEM_UNDO 选项会让内核记录一个与调用进程相关的UNDO记录,如果该进程崩溃,则根据这个进程的UNDO记录自动恢复相应信号量的计数值*/  };
 
参数3:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作返回:信号集标识符

3、设置集合中信号量的值:semctl        //参数一:集合标识符        //参数二:集合中第几个信号量        //参数三:对集合的操作命令        //    SETVAL:对信号量赋值        //参数四:根据命令传入不定个数的数据        semctl(semid, i, SETVAL, sem);   1) semid = semget(0x1024, NUM, IPC_CREAT|0664);2)定义联合体 union semun semunion semun{    int val;    struct semid_ds *buf;    unsigned short  *array;    struct seminfo  *__buf;};    union semun sem;    sem.val = 1;3)设置集合中信号量的值:semctl        semctl(semid, i, SETVAL, sem);



使用:pthread_mutex_t pmutex;pthread_mutex_t gmutex;
union semun{    int val;    struct semid_ds *buf;    unsigned short  *array;    struct seminfo  *__buf;};
#define NUM 5//用来保存信号量集合的标识符int semid = -1;//获得筷子void getChopsticks(int num){    int left = num;    int right = (num+1)%NUM;    //成员一:操作集合中第几个信号量    //成员二:-1表示获得资源,1表示释放资源    //成员三:0表示若资源不满足则阻塞等待直到满足为止    struct sembuf sem[2] = {{left, -1, 0}                            , {right, -1, 0}};    //通过结构体指定的操作来操作集合中的信号量    semop(semid, sem, 2);}//放下筷子void putChopsticks(int num){    int left = num;    int right = (num+1)%NUM;    //成员一:操作集合中第几个信号量    //成员二:-1表示获得资源,1表示释放资源    //成员三:0表示若资源不满足则阻塞等待直到满足为止    struct sembuf sem[2] = {{left, 1, 0}                            , {right, 1, 0}};    //通过结构体指定的操作来操作集合中的信号量    semop(semid, sem, 2);}
void *run(void *arg){    int num = (int)arg;    while (1)    {        printf("第%d个哲学家正在思考...\n", num+1);        sleep(1);        //获得筷子吃饭        pthread_mutex_lock(&gmutex);        getChopsticks(num);        printf("第%d个哲学家获得筷子吃饭...\n", num+1);        pthread_mutex_unlock(&gmutex);        sleep(1);        pthread_mutex_lock(&pmutex);        putChopsticks(num);        printf("第%d个哲学家放下筷子...\n", num+1);        pthread_mutex_unlock(&pmutex);        sleep(1);    }}
int main(void){    int i = 0;    //创建信号量集合    //参数一:使用一个十六进制的整数作为该集合的名字    //        名字可以重复    //参数二: 设置该集合中信号量的个数    //IPC_CREAT|0664:创建集合并指定操作权限    //成功返回该集合的标识符,    //通过标识符来唯一确定集合    semid = semget(0x1024, NUM, IPC_CREAT|0664);    union semun sem;    sem.val = 1;    for (i = 0; i < NUM; i++)    {        //设置集合中信号量的值        //参数一:集合标识符        //参数二:集合中第几个信号量        //参数三:对集合的操作命令        //    SETVAL:对信号量赋值        //参数四:根据命令传入不定个数的数据        semctl(semid, i, SETVAL, sem);    }    pthread_t thr[NUM];    //创建五个哲学家线程    for (i=0; i<NUM; i++)    {        pthread_create(thr+i, NULL, run, (void*)i);    }    //等待线程结束    for (i=0; i<NUM; i++)    {        pthread_join(thr[i], NULL);    }    return 0;}