免费注册 查看新帖 |

Chinaunix

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

[进程管理] pthread_mutex_lock故障 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-01-07 14:37 |只看该作者 |倒序浏览
本帖最后由 tqyou85 于 2013-03-01 14:13 编辑

代码中有个mutex锁用于两个进程间同步互斥,mutex位于shmem中,并且设置了优先级翻转属性。
两个进程的不同线程竞争时,出现异常。gdb调试发现,当前mutex内容如下:
  1. (gdb) p *mutex
  2. $3 = {__data = {__lock = -2147482930, __count = 1, __owner = 701, __kind = 160, __nusers = 1649, {__spins = 0, __list = {__next = 0x0}}},
  3.   __size = "\200\000\002\316\000\000\000\001\000\000\002\275\000\000\000\240\000\000\006q\000\000\000", __align = -2147482930}
复制代码
701为线程1的tid,另一个线程的tid为718.
查看线程1的堆栈,发现线程1状态如下:
  1. (gdb) bt
  2. #0  0x0ffaaa44 in __pthread_mutex_lock_full () from /lib/libpthread.so.0
复制代码
线程2状态如下:
  1. (gdb) bt
  2. #0  0x0ffb25a0 in __pause_nocancel () from /lib/libpthread.so.0
  3. #1  0x0ffaad28 in __pthread_mutex_lock_full () from /lib/libpthread.so.0
复制代码
研究了下glibc和linux futex的源码,mutex_lock进入到__pause_nocancel状态应该是系统调用到内核返回了ESRCH或EDEADLK,两个任务都没有异常退出,所以推断系统调用应该是返回了EDEADLK(11),但是为什么会返回这样的错误,以及内核futex是怎么处理的,还是弄不明白。

另外,查看内核futex源码,对于进程间的mutex,需要获取虚拟地址对应的物理地址的page描述符,由page描述符构造hash值:
get_futex_key --> get_user_pages_fast, 这个函数中有is_hugepd的判断,我的代码中对shmem设置了SHM_HUGETLB的属性,不知道这个有没有什么影响?

而且上述mutex的故障在shmem设置了SHM_HUGETLB的属性时,跑某些业务的时候必现。去掉SHM_HUGETLB的属性,正常。

使用的内核版本:2.6.34.12,并且打了内核实时性patch
powerpc平台

大虾请帮忙看看,非常感谢!

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
2 [报告]
发表于 2013-01-07 15:09 |只看该作者
我觉得这类错误不至于跟到内核里面去吧, 与其怀疑 pthread_mutex 或者 futex 实现存在错误, 不如多看看自己用户层的代码有没有 bug

论坛徽章:
4
天秤座
日期:2013-10-18 13:58:33金牛座
日期:2013-11-28 16:17:01辰龙
日期:2014-01-14 09:54:32戌狗
日期:2014-01-24 09:23:27
3 [报告]
发表于 2013-01-07 15:11 |只看该作者
进程之间的同步,用线程的锁,能顶得住么?

论坛徽章:
0
4 [报告]
发表于 2013-01-07 15:17 |只看该作者
回复 2# zylthinking
用户空间的代码逻辑很简单,反复review过多次了。不是怀疑mutex及内核实现有问题,只是希望能找到出现这种状况的原因。


   

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
5 [报告]
发表于 2013-01-07 15:31 |只看该作者
tqyou85 发表于 2013-01-07 15:17
回复 2# zylthinking
用户空间的代码逻辑很简单,反复review过多次了。不是怀疑mutex及内核实现有问题,只 ...


futex 看看这个吧, 我没有分析完, http://blog.chinaunix.net/uid-7190305-id-3051059.html, 不知有无帮助

楼上有人问了, 你们不会使用的非 shared 的mutex 吧, 貌似 private mutex 和 shared mutex 确实处理不同, 不知道为何会不同, 但我想应该不是将 mutex 放入 shm 就可以的, 否则, 也就没必要有这个属性了

论坛徽章:
0
6 [报告]
发表于 2013-01-07 15:58 |只看该作者
本帖最后由 tqyou85 于 2013-01-08 09:19 编辑

回复 5# zylthinking
多谢指导,先研究下。
我代码中mutex使用的是shared的,设置了PTHREAD_PROCESS_SHARED属性。
将mutex放在shmem,是为了跨进程能访问到这个内存地址。


private mutex和shared mutex使用不同,是因为futex要用锁的虚拟地址做hash值,如果是进程内的锁,则通过锁的虚拟地址+任务mm指针值+锁在页内偏移;如果是进程间的锁,则会获取锁虚拟地址对应物理地址的page描述符,由page描述符构造hash值。
这样计算的原因是进程间的锁在各个进程内虚拟地址可能是不同的,但都映射到同一个物理地址,对应同一个page描述符。所以,内核使用它来定位是否同一个锁。


   

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
7 [报告]
发表于 2013-01-08 08:27 |只看该作者
回复 6# tqyou85
期待有分析结果。。。

不过感觉自己代码bug的概率较大。因为之前用过进程间锁,没有出现过问题。当然也可能没有进入这种竞态。。。

   

论坛徽章:
0
8 [报告]
发表于 2013-01-09 11:53 |只看该作者
#define EDEADLK         35      /* Resource deadlock would occur */

看代码, 程序已经mutex lock了,然后再次再次想去lock,就返回这个。

这个mutex lock不允许重复 lock的。检查一下你的代码有没有这种可能咯

论坛徽章:
0
9 [报告]
发表于 2013-02-27 15:14 |只看该作者
回复 8# hmsghnh
检查了自己代码中mutex的使用,逻辑很简单,基本上都是每个线程拿锁,事情干完了,解锁。lock和unlock的调用都在一个函数中实现的。不会出现lock未unlock的情形。

   

论坛徽章:
0
10 [报告]
发表于 2013-02-27 21:48 |只看该作者
只说一下gdb的结果,

__count值表示信号量的嵌套加锁次数   =1
__owner表示信号量的拥有者             = 701
__nusers表示信号量加锁成功的线程数 =1649

__lock由2部分组成,bit 31~28表示flag,目前c库中只使用了bit31和bit30,bit31为1时表示
当前互斥锁有1个以上的线程(或进程)在等待获取该锁(FUTEX_WAITERS),bit30 为1时表示锁的拥有者已经退
出(FUTEX_OWNER_DIED); Bit 27~0表示加锁者的线程id

__lock   = 0x800002ce bit31为1,bit0-bit27是线程id,这里是718
这里和__owner字段对不上

我这边看到glibc版本, 如果发现线程加锁成功后,lock字段里的线程号和owner对不上,是会打印告警的
并且进到你gdb出来的那个什么pause函数里。
        if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) && (mutex->__data.__owner != (mutex->__data.__lock & FUTEX_TID_MASK)))
        {
                fprintf(stderr,"FUNC: %s; LINE: %d; mutex lock not equal owner: thread ID is %d, mutex addr is 0x%p, __lock is %d, __owner is %d, __count is %d, __nusers is %d, __kind is %d\n",
                                                                __FUNCTION__, __LINE__, id, mutex, mutex->__data.__lock, mutex->__data.__owner, mutex->__data.__count, mutex->__data.__nusers, mutex->__data.__kind
                                                                );
                while (1)
                                pause_not_cancel ();
        }

现在有点怀疑是内核futex处理的问题了。。
你的内核版本是多少

你是不是也在csdn的blog给我发过消息问这个问题。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP