c++ - 这种基于线程 ID 的同步是否安全整洁?

标签 c++ multithreading synchronization atomic

我编写了一个小的 AI 程序来解决 IQ Twist 难题。然后作为练习,我将其并行化。这是来源: IQTwist Resolver .

搜索解决方案的算法是递归的。

我在递归函数的关键部分(将找到的形状收集到成员数组)中使用了基于线程 ID 的同步。我指的关键部分:

bool IQTwistResolver::searchForSolution(const int type, const uint32 a_union)
{
    if (m_stopSearch) //make all other threads unwind recursion and finish
        return false;    

    if (TYPES_COUNT == type) //all types reached and solved - end recursion
    {
        m_mutex.lock();
        if (std::thread::id::id() == m_firstFinder || std::this_thread::get_id() == m_firstFinder)
        {
            m_firstFinder = std::this_thread::get_id();
            m_stopSearch = true;
        }
        m_mutex.unlock();
        return true; //return true to collect the solution and unwind
    }
    ...

我正在尝试向专家寻求建议:

这种方法是否有任何可能的弱点/缺陷或矫枉过正(也许我遗漏了一些更简单的解决方案)?

您会使用不同的“解决方案缓冲区”保护方法吗?

也许您会使用完全不同的并行化方案(这也值得了解)?

最佳答案

您的解决方案应该按预期工作,但是,使用 std::mutex是最通用和最昂贵的解决方案。

另一种选择是使用 std::call_once 这确保只有第一个线程进行调用。 IE。第一个找到解决方案的线程将设置搜索结果的值。

或者,您可以使用 std::atomic避免使用互斥锁。而不是线程 ID,线程特定变量的地址就足以区分线程。

例如:

#include <iostream>
#include <atomic>
#include <thread>

class FirstThread {
    static thread_local std::thread::id const thread_id_;
    std::atomic<std::thread::id const*> first_{0};

public:
    std::thread::id const& id() const noexcept {
        return thread_id_;
    }

    bool try_become_first() noexcept {
        std::thread::id const* expected = 0;
        return first_.compare_exchange_strong(expected, &thread_id_, std::memory_order_relaxed, std::memory_order_relaxed);
    }

    bool is_first() const noexcept {
        return first_.load(std::memory_order_relaxed) == &thread_id_;
    }
};

thread_local std::thread::id const FirstThread::thread_id_ = std::this_thread::get_id();

int main() {
    FirstThread ft;

    auto f = [&ft]() {
        ft.try_become_first();
        std::cout << "thread " << ft.id() << " is first: " << ft.is_first() << '\n';
    };
    f();
    std::thread(f).join();
}

输出:

thread 139892443997984 is first: 1
thread 139892384220928 is first: 0

注意如果不需要std::this_thread::get_id()返回的真实线程id , 你可以只使用线程特定的地址 bool识别不同的线程。

关于c++ - 这种基于线程 ID 的同步是否安全整洁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58149658/

相关文章:

ruby-on-rails - 记录数据更改以进行同步

c++ - 一旦成为标准的一部分——boost 库会失去其 boost 命名空间并移至 std 吗?

Java:异步并发写入磁盘

C# - 如何获得互斥量的所有者名称

java - 如何在 Java 5 中使用 ExecutorService 实现任务优先级?

java - 为这种情况动态生成线程 Java

java - 在数组中建立 Happens-Before

c++ - 在构造函数上传递参数或在每个方法上传递它们

c++ - 如何从类中初始化数组并将值设置为第一个元素?

c++ - PugiXML C++ 换行符处理问题 : '\n\n' becomes '\\n\\n'