【问题标题】:c++11 thread pool works on windows - blocks on linuxc++11线程池在windows上工作——linux上的blocks
【发布时间】:2015-07-15 14:19:24
【问题描述】:

编辑
我通过在 Shared 结构中使用单个互斥体变量而不是 Unique 中的多个互斥体解决了我的问题。如果有人理解为什么这样有效而另一个人不(可靠地)我会很乐意接受答案。
编辑

我用 c++11 线程写了一个简单的线程池。在 Windows 上它按预期运行,但在 linux 上它会阻塞。我假设我编程错误,它只是巧合地在 Windows 上运行。

这个想法是创建一次池并多次调用 run() ,它在所有可用线程上运行一次程序,然后返回而不破坏线程。然后线程等待下一次运行,依此类推。

在 Windows 上,我每次尝试都可以。然而,在 linux 上,只有一个线程开始执行程序,之后什么也没有发生,所以 run() 永远不会返回。

我只包含了我的源代码的一个稍微精简的版本,因为我认为它可能足够小。如果有人有兴趣看一下,我怀疑代码部分中间的 loop() 和 wait_all() 是最相关的部分。我还包含了声明作为参考,以防变量类型从名称/上下文中不清楚。

Pool::Pool(uint32_t num_threads) : num_threads_(num_threads), uniques_(num_threads), threads_(num_threads) {
    shared_.end  = false;

    for (uint32_t i = 0; i < num_threads; ++i) {
        uniques_[i].wake = false;
        threads_[i] = std::thread(loop, std::ref(uniques_[i]), std::ref(shared_));
    }
}

void Pool::run(Program program) {
    shared_.program = program;
    wake_all();
    wait_all();
}

void Pool::wake_all() {
    for (size_t i = 0; i < uniques_.size(); ++i) {
        uniques_[i].wake = true;
    }

    shared_.wake_signal.notify_all();
}

void Pool::wait_all() {
    for (size_t i = 0; i < num_threads_; ++i) {
        std::unique_lock<std::mutex> locker(uniques_[i].lock);
        uniques_[i].done_signal.wait(locker, [&]{return !uniques_[i].wake;});
    }
}

void Pool::loop(Unique& unique, Shared& shared) {
    for (;;) {
        std::unique_lock<std::mutex> locker(unique.lock);
        shared.wake_signal.wait(locker, [&]{return unique.wake;});

        if (shared.end) {
            break;
        }

        // Do stuff... On linux only a single thread gets here
        shared.program();

        unique.wake = false;
        locker.unlock();
        unique.done_signal.notify_all();
    }
}

// Declaration
class Pool {
public:
    typedef std::function<void()> Program;
    Pool(uint32_t num_threads);
    void run(Program program);
private:
    void wake_all();
    void wait_all();

    struct Unique {
        std::condition_variable done_signal;
        std::mutex lock;
        bool wake;
    };

    struct Shared {
        Program program;
        std::condition_variable wake_signal;
        bool end;
    };

    uint32_t num_threads_;
    Shared shared_;
    std::vector<Unique> uniques_;
    std::vector<std::thread> threads_;

    static void loop(Unique& unique, Shared& shared);
};

【问题讨论】:

  • 您的谓词在wait_all 中倒退。您想等待wake 成为true,而不是false。此外,wake_all 函数修改共享状态(wake 布尔值)而不持有保护该状态的锁。
  • SharedUnique 类型对我来说似乎没有任何意义。 Shared 在条件变量旁边缺少互斥锁。你有没有在死锁状态下调试过你的代码?
  • @DavidSchwartz:wait_all 中的反向谓词是故意的。可能有点不清楚,但想法是在wake_all 中等待wake == true,在wait_all 中等待wake == false。 “唤醒我”和“我完成了”的变量加倍。至少这是计划。
  • @Yakk:我的意图是有一个信号可以唤醒所有线程。不能这样实现吗?
  • @DavidSchwartz 是的,但是有很多 unique 互斥锁。哪个守卫共享条件变量?据我所知,没有人能可靠地做到这一点。我的猜测是 B_old 不了解互斥锁、条件变量和它们所保护的消息之间的关系?当使用多线程代码时,测试是不够的。 “当我尝试时它起作用了”是在生产中失败的代码配方。测试、构建您的代码将正常运行的逻辑参数。

标签: linux windows multithreading c++11 clang


【解决方案1】:

您违反了拨打wait的标准要求:

void wait(unique_lock& lock);

要求:lock.owns_lock() 为真并且 lock.mutex() 被调用线程锁定,并且:

——没有其他线程正在等待这个 condition_variable 对象或

— lock.mutex() 为所有并发等待(通过等待或 timed_wait)线程提供的每个锁参数返回相同的值。

您可以同时等待线程,其lock 引用不同的mutex。所以你不满足在condition_variable 上调用wait 的先决条件。

我相信你可以使用condition_variable_any,它没有这个要求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-10
    • 2013-03-23
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多