免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6939 | 回复: 16
打印 上一主题 下一主题

apue中父子进程同步的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-08-29 16:46 |只看该作者 |倒序浏览
本帖最后由 cryingbaby304 于 2011-09-06 08:37 编辑

执行下诉代码,父进程counter = 2后 就死锁了,而使用apue的程序清单15-3中用管道实现的另一套TELL,WAIT函数就正常执行,实在搞不清为什么,求解答,谢谢了!
如果需要可以贴出另外的一套TELL,WAIT函数

  1. #include "apue.h"
  2. #include <fcntl.h>
  3. #include <sys/mman.h>
  4. #include "list10_17.c"

  5. #define    NLOOPS        1000
  6. #define    SIZE        sizeof(long)    /* size of shared memory area */

  7. static int
  8. update(long *ptr)
  9. {
  10.     return((*ptr)++);    /* return value before increment */
  11. }

  12. int
  13. main(void)
  14. {
  15.     int        fd, i, counter;
  16.     pid_t    pid;
  17.     void    *area;

  18.     if ((fd = open("/dev/zero", O_RDWR)) < 0)
  19.         err_sys("open error");
  20.     if ((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
  21.       fd, 0)) == MAP_FAILED)
  22.         err_sys("mmap error");
  23.     close(fd);        /* can close /dev/zero now that it's mapped */

  24.     TELL_WAIT();

  25.     if ((pid = fork()) < 0) {
  26.         err_sys("fork error");
  27.     } else if (pid > 0) {            /* parent */
  28.         for (i = 0; i < NLOOPS; i += 2) {
  29.             if ((counter = update((long *)area)) != i)
  30.                 err_quit("parent: expected %d, got %d", i, counter);
  31.             printf("%d\n",counter);//the added new line
  32.             TELL_CHILD(pid);
  33.             WAIT_CHILD();
  34.         }
  35.     } else {                        /* child */
  36.         for (i = 1; i < NLOOPS + 1; i += 2) {
  37.             WAIT_PARENT();
  38.             if ((counter = update((long *)area)) != i)
  39.                 err_quit("child: expected %d, got %d", i, counter);
  40.             TELL_PARENT(getppid());
  41.         }
  42.     }
  43.     exit(0);
  44. }
复制代码

  1. //list10_17.c
  2. #include "apue.h"
  3. static volatile sig_atomic_t sigflag;
  4. static sigset_t newmask,oldmask,zeromask;

  5. static void sig_usr(int signo)
  6. {
  7.     sigflag = 1;
  8. }

  9. void TELL_WAIT(void)
  10. {
  11.     if(signal(SIGUSR1,sig_usr) == SIG_ERR)
  12.         err_sys("signal(SIGUSR1) error");
  13.     if(signal(SIGUSR2,sig_usr) == SIG_ERR)
  14.         err_sys("signal(SIGUSR2) error");
  15.     sigemptyset(&zeromask);
  16.     sigemptyset(&newmask);
  17.     sigaddset(&newmask,SIGUSR1);
  18.     sigaddset(&newmask,SIGUSR2);
  19.     if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)
  20.         err_sys("SIG_BLOCK error");
  21. }

  22. void TELL_PARENT(pid_t pid)
  23. {
  24.     kill(pid,SIGUSR2);
  25. }

  26. void WAIT_PARENT(void)
  27. {
  28.     while(sigflag == 0)
  29.         sigsuspend(&zeromask);
  30.     sigflag = 0;
  31.     if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0)
  32.         err_sys("SIG_SETMASK error");
  33. }

  34. void TELL_CHILD(pid_t pid)
  35. {
  36.     kill(pid,SIGUSR1);
  37. }

  38. void WAIT_CHILD(void)
  39. {
  40.     while(sigflag == 0)
  41.         sigsuspend(&zeromask);
  42.     sigflag = 0;
  43.     if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0)
  44.         err_sys("SIG_SETMASK error");
  45. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2011-08-29 16:58 |只看该作者
求解答{:3_198:}

论坛徽章:
0
3 [报告]
发表于 2011-08-30 11:25 |只看该作者
没人回答吗

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
4 [报告]
发表于 2011-09-02 12:27 |只看该作者
执行下诉代码,父进程counter = 2后 就死锁了,而使用apue的程序清单15-3中用管道实现的另一套TELL,WAIT函数 ...
cryingbaby304 发表于 2011-08-29 16:46



    不会呀,我这挺正常的,测试代码:http://code.google.com/p/code-fragment/source/browse/C/sync.c

论坛徽章:
0
5 [报告]
发表于 2011-09-03 11:07 |只看该作者
回复 4# MMMIX
对比我俩的代码,终于发现问题所在
当我把TELL_WAIT函数中的两个signal函数调用,换成如同你代码中的那样,用sigaction函数调用处理,结果就不会出现死锁了
难道是signal函数的原因,我的执行环境是centos5.6,编译器是gcc4.1.2
APUE中说signal的语义与实现有关,可能是可靠信号语义也可能是不可靠信号语义
求解答,同时非常感谢你的回答

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
6 [报告]
发表于 2011-09-03 11:16 |只看该作者
本帖最后由 MMMIX 于 2011-09-03 16:40 编辑
回复  MMMIX
对比我俩的代码,终于发现问题所在
当我把TELL_WAIT函数中的两个signal函数调用,换成如同你 ...
cryingbaby304 发表于 2011-09-03 11:07



    問題還是出在 WAIT_PARENT(), WAIT_CHILD() 的實現上,其中有 race condition:在進入 sigsuspend 之前,用來喚醒它的信號應該處於 blocked 狀態,否則若是在檢查之後 (while (sigflag == 0) 之後),進入 sigsuspend() 之前該信號到來並被處理了,那麼此時再進入 sigsuspend() 就無法被喚醒。
參見:http://www.cs.ui.ac.id/WebKuliah ... ibc/Sigsuspend.html

代碼見:http://code.google.com/p/code-fragment/source/browse/C/sync.c

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
7 [报告]
发表于 2011-09-03 19:09 |只看该作者
回复 1# cryingbaby304


    APUE 中這幾個通過 signal 實現的進程同步函數,是不适合用在循環中的,也即 WAIT_PARENT(), WAIT_CHILD() 調用一次行為正確,在一個進程中多次調用(APUE2 中也從沒有這麼用過)的話就會出現 race condition,這種情況下要讓其行為正確,就要把 TELL_WAIT() 中的 sigprocmask() 在 WAIT_PARENT(), WAIT_CHILD() 的 while 語句前各放一份。

修改後代碼:http://code.google.com/p/code-fragment/source/browse/C/sync.c

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
8 [报告]
发表于 2011-09-03 19:26 |只看该作者
回复 7# MMMIX


    又看了下書,這個問題 APUE2 的 Section 10.16 在開頭就講了。

论坛徽章:
0
9 [报告]
发表于 2011-09-05 09:16 |只看该作者
回复 8# MMMIX


    不好意思,前几天开学,没时间看回复,现在才看……再次感谢你的回答

1.没有把signal换成sigaction,只是如你所说在sigsuspend前设置对应的信号屏蔽,结果一样父进程输出到2后死锁
2.在 1 的基础上把signal换成sigaction,则正常执行
3.在 2 的基础上去掉sigsuspend前的信号屏蔽设置,也能正常执行

所以,感觉还是signal函数的问题。

4.我觉得,在sigsuspend前加上对应的信号屏蔽,还是有问题,因为信号有可能在执行sigprocmask之前就到来,
那sigsuspend还是会因为接收不到指定信号,一直不会被唤醒。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
10 [报告]
发表于 2011-09-05 20:09 |只看该作者
1.没有把signal换成sigaction,只是如你所说在sigsuspend前设置对应的信号屏蔽,结果一样父进程输出到2后死锁
2.在 1 的基础上把signal换成sigaction,则正常执行
3.在 2 的基础上去掉sigsuspend前的信号屏蔽设置,也能正常执行

你說的這些我一個都重現不了。

環境:

  1. lee@debian:~/code-fragment/C$ getconf GNU_LIBC_VERSION
  2. glibc 2.11.2
  3. lee@debian:~/code-fragment/C$ uname -a
  4. Linux debian 2.6.30-2-686 #1 SMP Fri Dec 4 00:53:20 UTC 2009 i686 GNU/Linux
  5. lee@debian:~/code-fragment/C$ gcc --version
  6. gcc (GCC) 4.1.3 20080704 (prerelease) (Debian 4.1.2-27)
复制代码
4.我觉得,在sigsuspend前加上对应的信号屏蔽,还是有问题,因为信号有可能在执行sigprocmask之前就到来,
那sigsuspend还是会因为接收不到指定信号,一直不会被唤醒。
cryingbaby304 发表于 2011-09-05 09:16

就算信號在 sigprocmask() 之前到來(並且沒有調用對應的 signal handler,此時它處於 pending),在進入 sigsuspend() 的時候這個信號就會被 delivery,sigsuspend() 會立即退出。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP