免费注册 查看新帖 |

Chinaunix

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

[Linux] 多个进程使用一个有名信号量来互斥,其中一个进程sem_wait时漰溃的话。。。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-03-19 22:12 |只看该作者 |倒序浏览
本帖最后由 BsiIce 于 2015-03-19 22:12 编辑

实际上是这样的,
有一个共享库,库中的一个函数不能重入,这个函数被多个进程执行时要做互斥处理,
互斥处理使用的是有名信号量,
有多个进程使用这个库,
其中一个进程在执行库中的函数期间正好漰溃,导致了sem_post没有执行,因此其它进程调用库中的这个函数时就都阻塞了,
再将被杀的进程起来也是阻塞的。
请问,这种情况下我应该怎么处理来保证那些进程正常运行?程序设计上是否存在问题?

在Linux下我也经常杀死进程,但从没遇到过这种情况。

这个附件是抽象出的示例程序:
kill-9_one_process_of_processes_that_using_a_same_shared_lib.tar.bz2 (1.13 KB, 下载次数: 24)
运行方法为:
解压后进入kill-9_one_process_of_processes_that_using_a_same_shared_lib,
执行make
进入bin,
执行./run.sh,此时会有“A: calling start”“A: calling end”和“B: calling start”“B: calling end”交替出现,一对start和end就是一次库中的函数的执行,
在刚出现“A: calling start”且还没出现“A: calling end”执行killall -9 A将A进程杀死,
此时,B进程永久阻塞了,
再使用命令LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./A将A进程起来,A进程也永久阻塞。
执行上述内容后,要想能正常重新执行,需要执行./kill.sh./rm_sem_file.sh

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
2 [报告]
发表于 2015-03-23 13:15 |只看该作者
回复 1# BsiIce


    这样确实会死锁的,POSIX semaphores的sem_wait,在程序崩溃时,并没有释放,此时再调用sem_wait就会死锁,这个就是很危险的事情,我们在一个项目中评估后使用的加锁是flock,这个接口,在程序崩溃后,因为所有打开的文件描述符关掉,会自动释放锁;另外你可以选择System V semaphore,在semop是可以设置SEM_UNDO,该属性也可以保证程序退出时,加锁的会被释放(我们那个项目中不支持System V semaphore)。

论坛徽章:
0
3 [报告]
发表于 2015-04-19 10:09 |只看该作者
本帖最后由 BsiIce 于 2015-04-19 10:55 编辑

回复 2# 羽剑天涯

抱歉这么晚才来。
非常感谢你的回复!
用flock解决了我的问题,就是存在点不解的地方,flock会存在竞争。(后来上网搜索,发现lockf更好,posix的,但也会存在竞争)
我把lib.c改为如下:
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. #include <sys/stat.h>
  5. #include <sys/file.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include "log.h"
  9. #include "lib.h"

  10. #define FLOCK_FILENAME  "/tmp/flock_1503191728"

  11. void libfunc(const char *caller)
  12. {
  13.    int fd = -1;
  14.    int ret = -1;
  15.    fd = open(FLOCK_FILENAME, O_RDWR | O_CREAT, 0644);
  16.    if (-1 == fd)
  17.    {
  18.       PRINTF("%s: open error: %s!\n", caller, strerror(errno));
  19.    }
  20.    ret = flock(fd, LOCK_EX);
  21.    if (-1 == ret)
  22.    {
  23.       PRINTF("%s: flock LOCK_EX error: %s!\n", caller, strerror(errno));
  24.    }
  25.    PRINTF("%s: calling start\n", caller);
  26.    sleep(2);
  27.    PRINTF("%s: calling end\n", caller);
  28.    ret = flock(fd, LOCK_UN);
  29.    if (-1 == ret)
  30.    {
  31.       PRINTF("%s: flock LOCK_UN error: %s!\n", caller, strerror(errno));
  32.    }
  33.    ret = close(fd);
  34.    if (-1 == ret)
  35.    {
  36.       PRINTF("%s: close error: %s!\n", caller, strerror(errno));
  37.    }
  38.    //ret = unlink(FLOCK_FILENAME);
  39.    //if (-1 == ret)
  40.    //{
  41.    //   PRINTF("%s: unlink: %s!\n", caller, strerror(errno));
  42.    //}
  43. }
复制代码
运行结果如下:
  1. libfunc:40: ./A: calling start
  2. libfunc:42: ./A: calling end
  3. libfunc:40: ./A: calling start
  4. libfunc:42: ./A: calling end
  5. libfunc:40: ./B: calling start
  6. libfunc:42: ./B: calling end
  7. libfunc:40: ./A: calling start
  8. libfunc:42: ./A: calling end
  9. libfunc:40: ./A: calling start
  10. libfunc:42: ./A: calling end
  11. libfunc:40: ./B: calling start
  12. libfunc:42: ./B: calling end
  13. libfunc:40: ./B: calling start
  14. libfunc:42: ./B: calling end
  15. libfunc:40: ./B: calling start
  16. libfunc:42: ./B: calling end
复制代码
存在连续多次的A或B,不是交替的,目前我没找到解决办法。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
4 [报告]
发表于 2015-04-19 15:55 |只看该作者
回复 3# BsiIce


    竞争肯定是会存在的,所以才用锁啊,你说的是饥饿(某个进程或线程一直不能(或很)难获得锁)吧?不知道你测试代码怎么写的,见以下代码
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. #include <sys/stat.h>
  5. #include <sys/file.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include <pthread.h>

  9. #define FLOCK_FILENAME  "/tmp/flock_1503191728"

  10. void libfunc(const char *caller)
  11. {
  12.    int fd = -1;
  13.    int ret = -1;
  14.    fd = open(FLOCK_FILENAME, O_RDWR | O_CREAT, 0644);
  15.    if (-1 == fd)
  16.    {
  17.       printf("%s: open error: %s!\n", caller, strerror(errno));
  18.    }
  19.    ret = flock(fd, LOCK_EX);
  20.    if (-1 == ret)
  21.    {
  22.       printf("%s: flock LOCK_EX error: %s!\n", caller, strerror(errno));
  23.    }
  24.    printf("%s: calling start\n", caller);
  25.    sleep(2);
  26.    printf("%s: calling end\n", caller);
  27.    ret = flock(fd, LOCK_UN);
  28.    if (-1 == ret)
  29.    {
  30.       printf("%s: flock LOCK_UN error: %s!\n", caller, strerror(errno));
  31.    }
  32.    ret = close(fd);
  33.    if (-1 == ret)
  34.    {
  35.       printf("%s: close error: %s!\n", caller, strerror(errno));
  36.    }
  37.    usleep(1);
  38. }
  39. void *tfunc(void *arg)
  40. {
  41.         while (1) {
  42.                 libfunc(arg);
  43.         }
  44. }

  45. int main(int argc, char **argv)
  46. {
  47.         pthread_t a,b;
  48.         char *ms="m", *as="a", *bs="b";

  49.         pthread_create(&a,NULL,tfunc, as);
  50.         pthread_create(&b,NULL,tfunc, bs);

  51.         while (1) {
  52.                 libfunc(ms);
  53.         }

  54.         return 0;
  55. }
复制代码
测试的输出如下:
  1. a: calling start
  2. a: calling end
  3. m: calling start
  4. m: calling end
  5. b: calling start
  6. b: calling end
  7. a: calling start
  8. a: calling end
  9. b: calling start
  10. b: calling end
  11. m: calling start
  12. m: calling end
  13. a: calling start
  14. a: calling end
  15. b: calling start
  16. b: calling end
  17. m: calling start
  18. m: calling end
  19. a: calling start
复制代码
在libfuc的最后一个usleep,这句注释掉的话,输出如下:
  1. m: calling start
  2. m: calling end
  3. m: calling start
  4. m: calling end
  5. m: calling start
  6. m: calling end
  7. m: calling start
  8. m: calling end
  9. a: calling start
  10. a: calling end
  11. a: calling start
  12. a: calling end
  13. a: calling start
  14. a: calling end
  15. a: calling start
  16. a: calling end
  17. a: calling start
  18. a: calling end
  19. a: calling start
  20. a: calling end
  21. m: calling start
  22. m: calling end
  23. a: calling start
  24. a: calling end
  25. a: calling start
  26. a: calling end
  27. a: calling start
  28. a: calling end
  29. a: calling start
  30. a: calling end
  31. m: calling start
  32. m: calling end
  33. b: calling start
  34. b: calling end
  35. b: calling start
  36. b: calling end
  37. b: calling start
  38. b: calling end
  39. b: calling start
复制代码
这个在测试程序中很正常,因为解锁以后,系统不一定会进行线程(进程)切换,即使别的线程(进程)已经等待在该锁上,而解锁后立刻又去加锁,此时该锁处于解锁状态,自然又被自己获得了,加入usleep会强制让出CPU,其他等待该锁的线程(进程)获得该锁的几率会大一些,不过同样,即使这样,也有可能:m让出后a获得锁,a让出后m获得锁,如此循环,b很难获得锁,除非自己再加入加锁的排队调度算法。

论坛徽章:
0
5 [报告]
发表于 2015-04-19 18:34 |只看该作者
回复 4# 羽剑天涯

叫饥饿啊,谢谢赐教了!
我发帖之前也加usleep试过了,就不存在饥饿了,
不过用posix sem不加usleep也不存在饥饿现象,不知道有没有符合这个特性flock之类的东西。

论坛徽章:
0
6 [报告]
发表于 2015-04-19 20:10 |只看该作者
使用usleep对于进程/线程少的时候还行,如果进程/线程很多的话使用usleep也会很容易饥饿的,能排队等锁就好了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP