1. 程式人生 > >pthread_sigmask 等控制執行緒的訊號掩碼

pthread_sigmask 等控制執行緒的訊號掩碼

示例1:

  1. /* 示例一:遮蔽訊號SIGINT

  2. 來源:http://www.leoox.com/?p=321

  3. 編譯:gcc pthread_sigmask1.c -lpthread

  4. 執行後,你發現你按下CTRL+C(觸發SIGINT訊號),這個程式根本停不下來。因為SIGINT訊號已經如我們所願被遮蔽掉了。

  5. */

  6. #include <pthread.h>

  7. #include <stdio.h>

  8. #include <sys/signal.h>

  9. #include <string.h>

  10. int main(int argc, char** argv)

  11. {

  12. pthread_t tid = pthread_self();

  13. sigset_t mask;

  14. sigemptyset(&mask);

  15. sigaddset(&mask, SIGINT);

  16. pthread_sigmask(SIG_SETMASK, &mask, NULL);//SIG_BLOCK SIG_SETMASK 會遮蔽掉SIGINT,但SIG_UNBLOCK不會遮蔽SIGINT

  17. printf("[main][%lu] working hard ...\n", tid);

  18. sleep(60);

  19. printf("[main][%lu] good bye and good luck!\n", tid);

  20. return 0;

  21. }

示例二:主程序創建出來的執行緒將繼承主程序的掩碼

  1. /* 示例二:主程序創建出來的執行緒將繼承主程序的掩碼

  2. 來源:http://www.leoox.com/?p=321

  3. 編譯:gcc pthread_sigmask2.c -lpthread

  4. 執行後,你可以發現,子執行緒果然接收不到pthread_kill傳送給自己的SIGINT訊號,

  5. 但可以收到SIGUSR1訊號!本來要休眠300s,但是收到了SIGUSR1訊號,

  6. 才休眠5秒就(提前294秒)醒來say goodbye了。

  7. 執行結果:

  8. [[email protected] thread]$ ./a.out

  9. [main][139999919077120] working hard ...

  10. >>> Thread[139999919068928] Running ......

  11. [main][139999919077120] send signal SIGINT ...

  12. Thread[139999919068928] catch signo = 10

  13. Thread[139999919068928] waitup(294), and say good bye!

  14. [main][139999919077120] good bye and good luck!

  15. [[email protected] thread]$

  16. */

  17. #include <pthread.h>

  18. #include <stdio.h>

  19. #include <sys/signal.h>

  20. #include <string.h>

  21. void handler(int signo)

  22. {

  23. pthread_t tid = pthread_self();

  24. printf("Thread[%lu] catch signo = %d\n", tid, signo);

  25. return;

  26. }

  27. void* run(void *param)

  28. {

  29. pthread_t tid = pthread_self();

  30. printf(">>> Thread[%lu] Running ......\n", tid);

  31. int rc = sleep(300);

  32. printf("Thread[%lu] waitup(%d), and say good bye!\n", tid, rc);

  33. return NULL;

  34. }

  35. int main(int argc, char** argv)

  36. {

  37. int ret = 0, i = 0;

  38. pthread_t tid = pthread_self();

  39. /* 註冊SIGUSR1訊號處理函式 */

  40. struct sigaction sa;

  41. memset(&sa, 0, sizeof(sa));

  42. sigemptyset(&sa.sa_mask);

  43. sa.sa_flags = 0;

  44. sa.sa_handler = handler;

  45. sigaction(SIGUSR1, &sa, NULL);

  46. /* 遮蔽訊號SIGINT */

  47. sigset_t mask;

  48. sigemptyset(&mask);

  49. sigaddset(&mask, SIGINT);

  50. pthread_sigmask(SIG_BLOCK, &mask, NULL);

  51. pthread_t threads[2];

  52. pthread_create(&threads[0], NULL, run, NULL);

  53. printf("[main][%lu] working hard ...\n", tid);

  54. sleep(1);

  55. /* 主程序創建出來的執行緒將繼承主程序的掩碼。所以子執行緒收不到SIGINT訊號。 */

  56. pthread_kill(threads[0], SIGINT);

  57. printf("[main][%lu] send signal SIGINT ...\n", tid);

  58. sleep(5);

  59. /* 子執行緒可以收到SIGUSR1訊號。 */

  60. pthread_kill(threads[0], SIGUSR1);

  61. pthread_join(threads[0], NULL);

  62. sleep(1);

  63. printf("[main][%lu] good bye and good luck!\n", tid);

  64. return 0;

  65. }

示例三:子執行緒可以後天培養自己對訊號的喜好

  1. /* 示例三:子執行緒可以後天培養自己對訊號的喜好

  2. 來源:http://www.leoox.com/?p=321

  3. 編譯:gcc pthread_sigmask3.c -lpthread

  4. 子執行緒天生繼承了主執行緒對訊號的喜好,但是自己可以通過後天的努力改變。

  5. 比如主執行緒喜歡SIGUSR1訊號,但是子執行緒可以不喜歡它,遮蔽掉SIGUSR1訊號。

  6. 由此可見,linux裡的每個執行緒有自己的訊號掩碼,所以使用pthread_kill給指定執行緒傳送訊號時,

  7. 一定謹慎設定好執行緒的訊號掩碼。

  8. 當然,用kill傳送訊號,在多執行緒環境下,kill所產生的訊號時傳遞到整個程序的,

  9. 並且所有執行緒都有機會收到這個訊號,但具體是哪個執行緒處理這個訊號,就不一定。

  10. 一般情況下,都是主執行緒處理這個訊號。

  11. 執行結果:

  12. [[email protected] thread]$ gcc pthread_sigmask3.c -lpthread

  13. [[email protected] thread]$ ./a.out

  14. [main][140613382825728] working hard ...

  15. >>> [1481543657]Thread[140613382817536] Running ......

  16. [main][140613382825728] send signal SIGUSR1 ...

  17. [1481543841]Thread[140613382825728] catch signo = 10 ... //子執行緒sleep期間,kill -SIGUSR1 2839

  18. [1481543861]Thread[140613382825728] catch signo = 10 ... done

  19. [1481543957]Thread[140613382817536] waitup(0), and say good bye!

  20. [main][140613382825728] good bye and good luck!

  21. [[email protected] thread]$

  22. */

  23. #include <pthread.h>

  24. #include <stdio.h>

  25. #include <sys/signal.h>

  26. #include <string.h>

  27. void handler(int signo)

  28. {

  29. pthread_t tid = pthread_self();

  30. printf("[%u]Thread[%lu] catch signo = %d ...\n", time(NULL), tid, signo);

  31. sleep(20);

  32. printf("[%u]Thread[%lu] catch signo = %d ... done\n", time(NULL), tid, signo);

  33. return;

  34. }

  35. void* run(void *param)

  36. {

  37. pthread_t tid = pthread_self();

  38. sigset_t mask;

  39. #if 1

  40. /* 這種情況下,本執行緒遮蔽所有的訊號 */

  41. sigfillset(&mask);

  42. #endif

  43. #if 0

  44. /* 這種情況下,本執行緒不遮蔽任何訊號 */

  45. sigemptyset(&mask);

  46. #endif

  47. #if 0

  48. /* 這種情況,本執行緒遮蔽以下的指定訊號 */

  49. sigemptyset(&mask);

  50. sigaddset(&mask, SIGINT);

  51. sigaddset(&mask, SIGQUIT);

  52. sigaddset(&mask, SIGHUP);

  53. sigaddset(&mask, SIGTERM);

  54. #endif

  55. pthread_sigmask(SIG_SETMASK, &mask, NULL);

  56. printf(">>> [%u]Thread[%lu] Running ......\n", time(NULL), tid);

  57. int rc = sleep(300);

  58. printf("[%u]Thread[%lu] waitup(%d), and say good bye!\n", time(NULL), tid, rc);

  59. return NULL;

  60. }

  61. int main(int argc, char** argv)

  62. {

  63. pthread_t tid = pthread_self();

  64. /* 註冊SIGUSR1訊號處理函式 */

  65. struct sigaction sa;

  66. memset(&sa, 0, sizeof(sa));

  67. sigemptyset(&sa.sa_mask);

  68. sa.sa_flags = 0;

  69. sa.sa_handler = handler;

  70. sigaction(SIGUSR1, &sa, NULL);

  71. pthread_t threads[1];

  72. pthread_create(&threads[0], NULL, run, NULL);

  73. printf("[main][%lu] working hard ...\n", tid);

  74. sleep(5);

  75. /* 子執行緒遮蔽了SIGUSR1訊號,所以子執行緒收不到SIGUSR1訊號。 */

  76. pthread_kill(threads[0], SIGUSR1);

  77. printf("[main][%lu] send signal SIGUSR1 ...\n", tid);

  78. sleep(5);

  79. pthread_join(threads[0], NULL);

  80. sleep(1);

  81. printf("[main][%lu] good bye and good luck!\n", tid);

  82. return 0;

  83. }

示例四:主執行緒收到訊號,沒處理完,又來一個訊號,子執行緒會處理嗎? 會!

  1. /* 示例四:主執行緒收到訊號,沒處理完,又來一個訊號,子執行緒會處理嗎? 會!

  2. 來源:http://www.leoox.com/?p=321

  3. 編譯:gcc pthread_sigmask4.c -lpthread

  4. 在一個命令列終端啟動a.out,在另一個命令列終端傳送4次SIGUSR1訊號給a.out程序

  5. 執行結果:

  6. [[email protected] thread]$ ./a.out

  7. [main][139796483913472] working hard ...

  8. >>> [1481545031]Thread[139796483905280] Running ...... //此時傳送四次kill -SIGUSR1 2886,2886為a.out的程序號

  9. [1481545054]Thread[139796483913472] catch signo = 10 ...

  10. [1481545055]Thread[139796483905280] catch signo = 10 ...

  11. [1481545056]Thread[139796483913472] catch signo = 10 ... done

  12. [1481545056]Thread[139796483913472] catch signo = 10 ...

  13. [1481545057]Thread[139796483905280] catch signo = 10 ... done

  14. [1481545057]Thread[139796483905280] catch signo = 10 ...

  15. [1481545058]Thread[139796483913472] catch signo = 10 ... done

  16. [1481545059]Thread[139796483905280] catch signo = 10 ... done

  17. >>> [1481545059]Thread[139796483905280] waitup(35), and say good bye!

  18. [main][139796483913472] good bye and good luck!

  19. [[email protected] thread]$

  20. */

  21. #include <pthread.h>

  22. #include <stdio.h>

  23. #include <sys/signal.h>

  24. #include <string.h>

  25. void handler(int signo)

  26. {

  27. pthread_t tid = pthread_self();

  28. printf("[%u]Thread[%lu] catch signo = %d ...\n", time(NULL), tid, signo);

  29. /*

  30. * 訊號處理函式休眠2秒,這期間再發送同一個訊號,觀察子執行緒的表現。

  31. */

  32. sleep(2);

  33. printf("[%u]Thread[%lu] catch signo = %d ... done\n", time(NULL), tid, signo);

  34. return;

  35. }

  36. void* run(void *param)

  37. {

  38. pthread_t tid = pthread_self();

  39. printf(">>> [%u]Thread[%lu] Running ......\n", time(NULL), tid);

  40. int rc = sleep(60);

  41. printf(">>> [%u]Thread[%lu] waitup(%d), and say good bye!\n", time(NULL), tid, rc);

  42. return NULL;

  43. }

  44. int main(int argc, char** argv)

  45. {

  46. pthread_t tid = pthread_self();

  47. /* 註冊SIGUSR1訊號處理函式 */

  48. struct sigaction sa;

  49. memset(&sa, 0, sizeof(sa));

  50. sigemptyset(&sa.sa_mask);

  51. sa.sa_flags = 0;

  52. sa.sa_handler = handler;

  53. sigaction(SIGUSR1, &sa, NULL);

  54. pthread_t threads[1];

  55. pthread_create(&threads[0], NULL, run, NULL);

  56. printf("[main][%lu] working hard ...\n", tid);

  57. pthread_join(threads[0], NULL);

  58. sleep(1);

  59. printf("[main][%lu] good bye and good luck!\n", tid);

  60. return 0;

  61. }

如果把void handler(int signo)函式中的sleep(2)註釋掉,執行結果如下:

[[email protected] thread]$ ./a.out  [main][140353429055232] working hard ... >>> [1481596389]Thread[140353429047040] Running ......     //此處傳送6次“kill -SIGUSR1 3123” [1481596401]Thread[140353429055232] catch signo = 10 ... [1481596401]Thread[140353429055232] catch signo = 10 ... done [1481596401]Thread[140353429055232] catch signo = 10 ... [1481596401]Thread[140353429055232] catch signo = 10 ... done [1481596402]Thread[140353429055232] catch signo = 10 ... [1481596402]Thread[140353429055232] catch signo = 10 ... done [1481596402]Thread[140353429055232] catch signo = 10 ... [1481596402]Thread[140353429055232] catch signo = 10 ... done [1481596402]Thread[140353429055232] catch signo = 10 ... [1481596402]Thread[140353429055232] catch signo = 10 ... done [1481596403]Thread[140353429055232] catch signo = 10 ... [1481596403]Thread[140353429055232] catch signo = 10 ... done >>> [1481596449]Thread[140353429047040] waitup(0), and say good bye! [main][140353429055232] good bye and good luck! [[email protected] thread]$ 可見,若子執行緒“沒空”(在sleep),主執行緒有空,訊號都給主執行緒處理了。