【发布时间】:2020-06-26 08:05:06
【问题描述】:
我正在编写一个程序,它有一个线程将点文件读入缓冲区,而许多线程从缓冲区中获取点并构造它们的八叉树。八叉树的每个多维数据集都由一个读写锁(又名 shared_mutex)保护,其中有 67 个(如果有两个线程,现在有)。如果文件太大,程序就会死锁,我很难调试它。其中一个锁在 gdb 中如下所示:
[6] = {_M_impl = {_M_rwlock = {__data = {__readers = 1,
__writers = 0, __wrphase_futex = 1, __writers_futex = 0, __pad3 = 0,
__pad4 = 0, __cur_writer = 0, __shared = 0, __rwelision = 0 '\000',
__pad1 = "\000\000\000\000\000\000", __pad2 = 0, __flags = 0},
__size = "\001\000\000\000\000\000\000\000\001", '\000' <repeats 46 times>, __align = 1}}},
大多数互斥锁的 __readers=1,一个有 __readers=3,一个有 __readers=4294967289 左右。这是没有意义的,因为只有两个线程,所以只有两个线程可以读取它们;在构建八叉树阶段,他们应该是写锁定而不是读锁定互斥锁,并且 -7 看起来像七个线程已经读解锁了互斥锁而没有先读锁定它。尝试在 __readers 上设置观察点不起作用;它使调试器崩溃,或类似的东西。
我为锁定和解锁写了一个包装器:
void lockBlockR(int block)
{
metaMutex.lock();
modReaders[block%modMutexSize]++;
metaMutex.unlock();
modMutex[block%modMutexSize].lock_shared();
}
void lockBlockW(int block)
{
modMutex[block%modMutexSize].lock();
}
void unlockBlockR(int block)
{
metaMutex.lock();
if (--modReaders[block%modMutexSize]<0)
cout<<"Read-unlocked "<<block<<" too many times\n";
metaMutex.unlock();
modMutex[block%modMutexSize].unlock_shared();
}
void unlockBlockW(int block)
{
modMutex[block%modMutexSize].unlock();
}
当程序挂起时,我查看了 modReaders,它全为零,然后又查看了 modMutex,它的大部分 __readers=1 和一个负数。我如何弄清楚发生了什么?
我正在运行 Eoan Ermine、Linux 5.3.0 和 libc 2.30。该程序是在 C++17 中使用 gcc 9.2.1 编译的。
我之前在 PerfectTIN (https://github.com/phma/perfecttin) 中使用过读写器锁和模锁池,但模池中的锁是普通互斥锁。
ETA:我添加了另一个名为 modWriters 的整数映射和一些调试语句,并在解锁未锁定的互斥锁时捕获了一个线程。不过,它是写锁定和写解锁,所以这并不能解释为什么 __readers 会搞砸了。
【问题讨论】:
标签: c++ multithreading c++17