首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当两个线程完全同时在同一个互斥体上尝试一个try_lock()时,会发生什么?

当两个线程完全同时在同一个互斥体上尝试一个try_lock()时,会发生什么?
EN

Stack Overflow用户
提问于 2019-07-04 18:44:51
回答 1查看 804关注 0票数 0

这是我的第二个帖子。我的第一篇文章是从入门到C级的大学毕业生。我希望这次我能做得更好。

我正在为我的研究开发一个随机模型,并在我的算法中寻找提高计算效率的方法。最近,一位同事向我介绍了多线程技术,并将其成功地应用到了一些不需要锁的算法中.

现在,我正在尝试修改/线程一种需要锁的算法。在我的文献/StackOverflow/google搜索中,我学到了很多关于互斥类的知识。然而,我所面临的问题似乎是独一无二的。就上下文而言,我能找到的最接近答案的就是这里:

当两个线程试图在完全相同的时间锁定相同的资源时会发生什么?

它仍然没有直接解决我将要问的问题。

我一直试图使用动态分配的指向互斥对象的指针数组来控制线程之间的内存访问。我的代码编译时没有警告/错误(编译w/标志-pthread -std=c++11),并且执行完美,直到抛出分段错误的线程算法。在使用lldb进行调查后,我发现抛出的异常如下:

11输出屏幕截图

经过进一步研究,我发现由lldb输出引用的线程都在同一个互斥对象上尝试一个try_lock(),因为包含该对象地址的指针数组被传递给每个线程。

我的问题与前面提到的职位类似:

当多个线程(多个)在完全相同的时间(处理器时钟的相同笔划)的同一个互斥体上尝试一个try_lock()时,会发生什么?较新的互斥类实现是否为这一看似灾难性的事件(即shard_mutex、timed_mutex等)提供了解决办法?

这件事最近让我心烦意乱,所以我会非常感激你的任何见解。对S/O社区的大力呼喊,感谢他们的帮助,在这篇文章上,以及对我作为一名程序员的成长所具有的宝贵价值的所有其他方面。

指向代码的链接:

4.git

错误发生在第751行或第857行的RVEdata.cpp中。

已修复但未解决:

我能够使用互斥对象来修复我的代码,而不是创建指向动态创建互斥对象的指针向量。其他用户在此提出了解决方案:

How can I use something like std::vector?

在我的第一次尝试(不成功)中,我试图创建一个指向互斥对象的数组,如下所示:

代码语言:javascript
复制
long int N = RuntimeVector.size(); //Varying size at runtime
std::mutex *MutexPtrs;
MutexPtrs = new std::mutex[N];

然后,我将新创建的数组作为指针传递给一个函数,该函数将指针传递给一个新线程,如下所示:

代码语言:javascript
复制
void SomeFunction(std::mutex *PosLocks[])
{
.
..
...

    SearchersPos.push_back(std::async(std::launch::async, &RVEdata::PositiveSearch, this, PosLocks));
}

使用此方法,代码并非在每次执行时都失败,但在使用EXC_BAD_ACCESS时却失败了90%。有趣的是,在每次执行失败时,当多个线程试图对同一个互斥对象进行try_lock时,都会引发错误的访问。它从未失败过,只有一个线程试图在一个单独的互斥体上运行一个try_lock。当我在我们的HPC上运行相同的代码时,失败发生的时间大约是95%,但我在gdb中找不到的信息与在lldb中的信息一样多(我对命令行gdb不太精通)。

PS -I在macOS HighSiera10.13.6,Apple版本10.0.0 (clang-1000.11.45.5)上运行。

EN

回答 1

Stack Overflow用户

发布于 2019-07-05 15:26:33

当多个线程(多个)在完全相同的时间(处理器时钟的相同笔划)的同一个互斥体上尝试一个try_lock()时,会发生什么?较新的互斥类实现是否为这一看似灾难性的事件(即shard_mutex、timed_mutex等)提供了解决办法?

这绝对没有什么灾难性的,,这就是的互斥对象。您还没有在互斥锁的工作方式中发现一个缺陷,select并没有中断。您应该阅读StackOverflow的创始人之一的编程的第一条规则

在我的第一次尝试(不成功)中,我试图创建一个指向互斥对象的数组,如下所示:

问题是,您正在创建两个互斥数组

代码语言:javascript
复制
std::mutex *PosLocks;
std::mutex *GndLocks;

PosLocks = new std::mutex[N];
GndLocks = new std::mutex[N];

但是,您要传递数组的地址

代码语言:javascript
复制
NetExists = FindNetwork(N, &PosLocks, &GndLocks);

它调用此函数:

代码语言:javascript
复制
bool RVEdata::FindNetwork(long int N, std::mutex *PosLocks[], std::mutex *GndLocks[])

现在您已经将std::mutex**参数传递给函数,它可以是指向互斥数组的指针,也可以是指向互斥的指针数组

然后您将它们作为mutex*数组访问,而不是以指向 mutex[]的指针访问

代码语言:javascript
复制
    if (PosLocks[i]->try_lock() == true)

PosLocks[i]对数组进行索引以获得mutex*,然后使用->运算符取消指针的引用。但那是向后的!您没有一个mutex*数组!

正如我在上面的评论中所说的,您只是访问数组不正确。这意味着程序试图将mutex对象锁定在没有mutex对象的某个地址上,因为您正在读取一个地址,该地址位于互斥对象的中间,而不是它的起始位置。

上面的行应该首先取消对指针的引用,以到达mutex[],然后将索引到数组中:

代码语言:javascript
复制
    if ((*PosLocks)[i].try_lock() == true)

或者更好的做法是,首先停止传递指向数组的指针,即将函数声明为:

代码语言:javascript
复制
bool RVEdata::FindNetwork(long int N, std::mutex PosLocks[], std::mutex GndLocks[])

并称之为:

代码语言:javascript
复制
NetExists = FindNetwork(N, PosLocks, GndLocks);

现在您只需直接访问数组:

代码语言:javascript
复制
    if (PosLocks[i].try_lock() == true)

更好的是,停止使用动态创建的数组:

代码语言:javascript
复制
std::vector<std::mutex> PosLocks;
std::vector<std::mutex> GndLocks;
// ...
NetExists = FindNetwork(N, PosLocks, GndLocks);
// ...

bool RVEdata::FindNetwork(long int N, std::vector<std::mutex>& PosLocks, std::vector<std::mutex>& GndLocks)
{
    // ...
    if (PosLocks[i].try_lock() == true)

如果没有混合数组和指针以及动态分配,问题就不会发生。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56893030

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档