c++ 是否有这样的情况:当另一个线程试图用lock_guard锁定一个已解锁的互斥对象时,先解锁再锁定它是有效的?

vltsax25  于 2023-05-02  发布在  其他
关注(0)|答案(1)|浏览(167)

我为这个糟糕的标题道歉,只是想找个人来确认我没有疯。
我最近偶然发现了一些已经使用多年的代码,没有人抱怨。我之所以研究它,是因为我在大量修改这个代码库时遇到了这个错误:

pthread_mutex_lock.c:90: ___pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.

经过一番挖掘,我发现了一个非常奇怪的(对我来说)互斥的用法。本质上:
1.两个线程从主线程派生并分离(两个线程在同一个线程中)。cpp文件,并共享全局声明的互斥体)
1.在一个似乎是第一个命中的线程中,互斥锁被解锁,然后在循环中暂停10秒锁定,根据评论“允许其他线程处理消息”。
1.可能第二个被命中的线程(首先生成,但等待接收数据)在switch语句中有一个case,该语句使用lock_guard锁定互斥体

我相信这是一个多方面的未定义行为,但我得到了一些反对意见,说它应该改变,因为我正在努力始终如一地最小限度地重现这个确切的错误。

我假设这是为了使互斥锁首先被循环线程解锁(从解锁状态,还没有数据供lock_guard线程处理),然后被锁定,并且将花费其大部分时间锁定,而lock_guard偶尔尝试锁定,并且必须等待循环将其解锁,此时它可以处理其数据,lock_guard超出作用域,锁返回给循环线程。
我认为导致我的错误的原因是;lock_guard线程比我的修改预期的更快地获得数据,因此lock_guard用例被触发,然后循环线程试图解锁另一个线程的互斥锁。
我正在寻找:

  • 确认它是UB来声明一个互斥体,然后在不锁定它的情况下解锁它
  • 如果循环线程在lock_guard持有互斥锁时解锁互斥锁,则确认它是UB
  • 确认我的假设是什么导致我的错误(我基本上已经知道前两个参考,但要确保我没有错过一些大的大脑做事情的方式,我不知道)
  • 也许有一个更好的方法来做到这一点,我会假设这可以通过首先锁定循环外的互斥体来解决?

我已经搜索了代码库,我可以看到mutex只使用了4次:当它被声明,当它在lock_guard中使用,当它被解锁,然后锁定,所以我的while我的MRE很短,我认为它基本上有它需要的一切。要演示如何使用此互斥:

#include <iostream>
#include <thread>
#include <mutex>
#include <unistd.h>

std::mutex data_mtx;

void lg_thread(){
  std::lock_guard<std::mutex> guard(data_mtx);

  usleep(10e6);
}

int main(int argc, char const* argv[]){
  std::thread t1(lg_thread);

  usleep(10000);

  for (int i = 0; i < 100; i++){
    data_mtx.unlock();
    usleep(500);
    data_mtx.lock();
  }

  return 0;
}
fumotvh3

fumotvh31#

我正在寻找:

  • 确认它是UB来声明一个互斥体,然后在不锁定它的情况下解锁它

解锁当前未被调用线程锁定/拥有的mutexundefined behavior,是的。

  • 如果循环线程在lock_guard持有互斥锁时解锁互斥锁,则确认它是UB

是的,是UB。见上文。

  • 确认我的假设是什么导致我的错误(我基本上已经知道前两个参考,但要确保我没有错过一些大的大脑做事情的方式,我不知道)

见上文。

  • 也许有个更好的办法

考虑使用std::condition_variable来协调线程。
我假设这可以通过首先锁定循环外的互斥体来解决?
是的。这样,如果main()先锁定mutex,那么lock_guard将阻塞,等待main()解锁它,如果lock_guard先锁定mutex,那么main()将阻塞,等待lock_guard解锁它。应该是这样

相关问题