• 系统编程 day08 信号函数(信号量的使用方法,申请信号量初始化信号量 销毁信号的函数 (signal 信号捕捉函数)


    1.线程同步-信号量

    信号量从本质上是一个非负整数计数器,通常被用来控制对公共资源的访问。     

    当可用的公共资源增加时,调用函数sem_post()增加信号量。 只有当信号量值大于0时,函数sem_wait()才能返回,并将信号量的值减1,当信号量等于0时,sem_wait()将被阻塞直到信号量的值大于0。 函数sem_trywait()是函数sem_wait()的非阻塞版本。


    2.信号量也就是操作系统中所用到的PV 原语,它广泛用于进程或线程间的同步与互斥。

    信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。     

    PV原语的工作原理:PV原语是对整数计数器信号量sem的操作。一次P操作使sem减一,而一次V操作使sem 加一。进程(或线程)根据信号量的值来判断是否对公共资源具有访问权限。当信号量sem 的值大于等于零时,该进程(或线程)具有公共资源的访问权限;相反,当信号量sem的值小于零时,该进程(或线程)就将阻塞直到信号量sem的值大于等于0 为止。


    3.sem_init用于创建无名信号量并初始化它的值

    头文件:#include

    原型:int sem_init(sem_t *sem,int pshared,unsigned int value);

    参数: sem:信号量 pshared:决定信号量能否在几个进程间共享。由于目前Linux还没有实现进程间共享信号量,所以这个值只能够取0     value:信号量初始化值

    返回值:成功:0       出错:-1


    4.sem_getvalue--得到信号量值

    头文件:#include

    原型:int sem_getvalue(sem_t *sem,int * val);

    参数:sem为指向信号灯的指针,val是用于存储所查询到的信号量值

    返回值:成功返回0,失败返回-1


    5.sem_destroy--清理信号量

    头文件:#include

    原型:int sem_destroy (sem_t * sem);

    参数:sem为指向信号量的指针

    返回值:成功返回0,失败返回-1


    6.sem_wait-等待共享资源   (  -1 函数)

    sem_trywait--等待共享资源

    参数:sem 指向信号灯的指针 返回值:若成功则返回0,否则返回-1。

    功能补充:可以用sem_wait来申请共享资源,sem_wait函数可以测试所指定信号灯的值,如果该值大于0,那就将它减1并立即返回。我们就可以使用申请来的共享资源了。如果该值等于0,调用线程就被进入睡眠状态,直到该值变为大于0,这时再将它减1,函数随后返回。sem_wait操作必须是原子的。

    sem_wait与sem_trywait的区别: sem_wait和sem_trywait相当于P操作,它们都能将信号量的值减一,两者的区别在于若信号量小于零时,

    sem_wait将会阻塞进程,  

    而sem_trywait则会立即返回


    int sem_post(sem_t *sem);    ( +1函数 )

    7.头文件:#include

    函数原形:int sem_post(sem_t *sem);

    参数:sem 指向信号灯的指针

    返回值:若成功则返回0,否则返回-1。

    功能补充:当一个线程使用完某个信号灯时,它应该调用sem_post来告诉系统申请的资源已经用完。本函数和sem_wait函数的功能正好相反,它把所指定的信号灯的值加1,然后唤醒正在等待该信号灯值变为正数的任意线程。


    89..代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include //信号量的使用的函数
    35. // 0.信号量的使用方法
    36. //1.申请信号量
    37. //2.初始化信号量
    38. //3.p 操作  -1操作
    39. //4.读写操作
    40. //5.v操作  +1操作
    41. //6.销毁信号量
    42. //
    43. int main(int argc,char *argv[])
    44. {
    45. //1.申请信号量
    46. sem_t sem;
    47. //2.初始化信号量
    48. if(sem_init(&sem,0,1)<0) //灯亮
    49. {
    50. perror("sem_init error\n");
    51. return -1;
    52. }
    53. else
    54. {
    55. printf("sem_init ok\n");
    56. }
    57. //查看信号量
    58. int value =0;
    59. sem_getvalue(&sem,&value);
    60. printf("1 value = %d\n",value);
    61. //3.p 操作  -1操作
    62. sem_wait(&sem); //关灯操作 (堵塞版)
    63. sem_getvalue(&sem,&value);
    64. printf("2 value = %d\n",value);
    65. int s=sem_post(&sem); //开灯操作
    66. if(s<0)
    67. {
    68. perror("sem_post error\n");
    69. }
    70. else
    71. {
    72. printf("sem_post ok\n");
    73. }
    74. while(sem_trywait(&sem)) //不堵塞版开灯操作
    75. {
    76. perror("sem_trywait error\n");
    77. sleep(1);
    78. }
    79. //4.读写操作
    80. printf("do something to resourme\n");
    81. //5.v操作  +1操作
    82. s=sem_post(&sem); //开灯操作
    83. if(s<0)
    84. {
    85. perror("sem_post error\n");
    86. }
    87. else
    88. {
    89. printf("sem_post ok\n");
    90. }
    91. sem_getvalue(&sem,&value);
    92. printf("3 value = %d\n",value);
    93. //6.销毁信号量
    94. sem_destroy(&sem);
    95. return 0;
    96. }

    9.程序功能: 把信号量的方法用到 线程之中

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include //信号量的使用的函数
    35. // 0.信号量的使用方法
    36. //1.申请信号量
    37. //2.初始化信号量
    38. //3.p 操作  -1操作
    39. //4.读写操作
    40. //5.v操作  +1操作
    41. //6.销毁信号量
    42. //
    43. int num=100;
    44. //1.申请信号量 (全局变量)
    45. sem_t sem;
    46. void * pthread_fun1(void *arg)//创建线程的函数 
    47. {
    48. while(sem_trywait(&sem)) //不堵塞版关灯操作
    49. {
    50. perror("fun1 sem_trywait error\n");
    51. sleep(1);
    52. }
    53. printf("this is %s %d %ld start \n",__func__,getpid(),pthread_self());
    54. for(int i=0;i<5;i++)
    55. {
    56. num+=1;
    57. printf("1111111 :%d\n",num);
    58. sleep(1);
    59. }
    60. printf("this is %s %d %ld end \n",__func__,getpid(),pthread_self());
    61. int s=sem_post(&sem); //开灯操作
    62. if(s<0)
    63. {
    64. perror("sem_post error\n");
    65. }
    66. else
    67. {
    68. printf("sem_post ok\n");
    69. }
    70. }
    71. void * pthread_fun2(void *arg)//创建线程的函数 
    72. {
    73. while(sem_trywait(&sem)) //不堵塞版关灯操作
    74. {
    75. perror("fun2 sem_trywait error\n");
    76. sleep(1);
    77. }
    78. printf("this is %s %d %ld start \n",__func__,getpid(),pthread_self());
    79. for(int i=0;i<5;i++)
    80. {
    81. num-=2;
    82. printf("22222222 :%d \n",num);
    83. sleep(1);
    84. }
    85. printf("this is %s %d %ld end \n",__func__,getpid(),pthread_self());
    86. int s=sem_post(&sem); //开灯操作
    87. if(s<0)
    88. {
    89. perror("sem_post error\n");
    90. }
    91. else
    92. {
    93. printf("sem_post ok\n");
    94. }
    95. }
    96. void * pthread_fun3(void *arg)//创建线程的函数 
    97. {
    98. while(sem_trywait(&sem)) //不堵塞版关灯操作
    99. {
    100. perror("fun3 sem_trywait error\n");
    101. sleep(1);
    102. }
    103. printf("this is %s %d %ld start \n",__func__,getpid(),pthread_self());
    104. for(int i=0;i<5;i++)
    105. {
    106. num+=3;
    107. printf("333333333 :%d\n",num);
    108. sleep(1);
    109. }
    110. printf("this is %s %d %ld end \n",__func__,getpid(),pthread_self());
    111. int s=sem_post(&sem); //开灯操作
    112. if(s<0)
    113. {
    114. perror("sem_post error\n");
    115. }
    116. else
    117. {
    118. printf("sem_post ok\n");
    119. }
    120. }
    121. int main(int argc,char *argv[])
    122. {
    123. //2.初始化信号量
    124. if(sem_init(&sem,0,1)<0) //灯亮
    125. {
    126. perror("sem_init error\n");
    127. return -1;
    128. }
    129. else
    130. {
    131. printf("sem_init ok\n");
    132. }
    133. //查看信号量
    134. //创建线程
    135. int value =0;
    136. sem_getvalue(&sem,&value);
    137. printf("1 value = %d\n",value);
    138. pthread_t tid1 =0;
    139. pthread_t tid2 =0;
    140. pthread_t tid3 =0;
    141. pthread_create(&tid1,NULL,pthread_fun1,NULL);
    142. pthread_create(&tid2,NULL,pthread_fun2,NULL);
    143. pthread_create(&tid3,NULL,pthread_fun3,NULL);
    144. pthread_join(tid1,NULL); //不接受子线程的退出状态
    145. pthread_join(tid2,NULL); //不接受子线程的退出状态
    146. pthread_join(tid3,NULL); //不接受子线程的退出状态
    147. //6.销毁信号量
    148. sem_destroy(&sem);
    149. return 0;
    150. }



    10.信号的介绍:

    1.信号定义:信号(signal):是进程之间相互传递消息的一种方法,信号全称为软中断信号,也称作软中断。信号用来通知进程发生了异步事件。 信号事件的发生有两个来源: 1硬件来源,比如我们按下了键盘或者其它硬件故障; 2软件来源,最常用信号相关系统函数是kill(), raise(), alarm()和setitimer()等函数,软件来源还包括一些非法运算等操作。  注意:信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。

    2进程对信号的处理

    进程可以通过三种方式来响应和处理一个信号: 1忽略信号:忽略某个信号,对该信号不做任何处理,就象未发生过一样。 2捕捉信号:是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理.//编程。 3执行缺省操作:对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止

    3Linux支持的信号列表



    11.信号发送与捕捉

    kill()和raise() kill函数同读者熟知的kill系统命令一样,可以发送信号给进程或进程组

    alarm()和pause()

    kill –l 命令查看系统支持的信号列表

    raise函数允许进程向自己发送信号

    alarm()也称为闹钟函数,它可以在进程中设置一个定时器。当定时器指定的时间到时,内核就向进程发送SIGALRM信号。

    pause()函数是用于将调用进程挂起直到收到信号为止。

     

     kill  函数:

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:kill 函数的测试
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. int main(int argc,char *argv[])
    36. {
    37. printf("%s start \n",__func__);
    38. //kill(getpid(),SIGKILL);
    39. //kill(getppid(),SIGKILL); //ctrl + d 关闭终端
    40. kill(getpid(),SIGTSTP);
    41. printf("%s end\n",__func__);
    42. return 0;
    43. }

    raise 函数 

    alarm 函数

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:信号的其他函数
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. //1.raise 只能给自己发信号
    36. //2.alarm 调用以后,内核在定的时间,到了之后,给本进程发送闹钟信号 (闹钟信号 的操作是终止本任务)
    37. //3.abort 终止 //核心已转储的函数
    38. //4.pause 让调用本函数的任务 停止 知道内核给本任务发送信号
    39. int main(int argc,char *argv[])
    40. {
    41. printf("%s start\n",__func__);
    42. //raise(SIGKILL);//杀死
    43. //raise(SIGTSTP);//暂停
    44. //raise(SIGINT);//终止
    45. alarm(5); //以秒为单位
    46. for(int i=1;i<=10;i++)
    47. {
    48. printf("this is alarm sig!\n");
    49. sleep(1);
    50. if(i==2)
    51. {
    52. //abort();
    53. pause();
    54. }
    55. }
    56. printf("%s end\n",__FILE__);//文件名字
    57. return 0;
    58. }


    12.信号的处理

    特定的信号是与相应的事件相联系的 一个进程可以设定对信号的相应方式

    信号处理的主要方法有两种 使用简单的signal()函数

     signal() 使用signal函数处理时,需指定要处理的信号和处理函数 使用简单、易于理解

    代码:

    1. /************************************************************************************************************************************************************************************************************************
    2. *文件名:
    3. *作 者:She001
    4. *时 间:
    5. *版 本:
    6. *作 用:signal 函数的使用
    7. ****************************************************************************************************************************************************************************************************************************/
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #include
    34. #include
    35. //1.signal
    36. //2.A 任务 给 B任务 发送信号 B任务有三种回应 1.忽略  2.捕获 3.缺省
    37. //
    38. //
    39. void sigfun(int signo)
    40. {
    41. if(signo ==SIGINT )
    42. {
    43. printf("file is ctrl + c\n");
    44. }
    45. else if(signo == SIGQUIT)
    46. {
    47. printf("file is ctrl + \\ \n");
    48. }
    49. else if(signo ==SIGTSTP)
    50. {
    51. printf("file is ctrl + z \n");
    52. }
    53. else if(signo=SIGALRM)
    54. {
    55. printf("alarm signal is buhuo1\n");
    56. }
    57. }
    58. int main(int argc,char *argv[])
    59. {
    60. printf("this is signal test start\n");
    61. signal(SIGINT,sigfun);
    62. signal(SIGQUIT,sigfun);
    63. signal(SIGTSTP,sigfun);
    64. signal(SIGALRM,sigfun);
    65. int num =20;
    66. alarm(5);
    67. //还原信号原来的功能 signal(SIGINT, SIG_DFL)
    68. //忽略信号的功能   singal(SIGINT, SIG_IGN);
    69. //可以捕获 alarm 函数的终止信号;
    70. while(num--)
    71. {
    72. printf("test num =%d\n",num);
    73. sleep(1);
    74. }
    75. printf("this is singal end \n");
    76. return 0;
    77. }

  • 相关阅读:
    软考 - 网络工程师考试大纲
    python学习笔记——集合
    【笔试题】【day8】
    三、c++代码中的安全风险-open
    Redis缓存和MySQL数据一致性方案详解
    微服务项目:尚融宝(13)(前端平台:搭建管理平台前端程序)
    试题二(15分)和试题三(15分) (软件设计师笔记)
    junit单元测试
    这家公司,太过恶心,今天必须曝光它!
    在VSCode中调试其他软件执行的python文件
  • 原文地址:https://blog.csdn.net/she666666/article/details/126254368