c ++ 11线程池适用于Windows - Linux上的块

时间:2021-04-02 07:06:20

EDIT
I solved my problem by using a single mutex variable in the Shared struct instead of the multiple mutexes in Unique. If someone understands why this works and the other one doesn't (reliably) I will gladly accept an answer.
EDIT

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

I wrote a simple thread pool with c++11 threads. On windows it behaves as intended but on linux it blocks. I assume that I programmed it wrong and it is just running on windows by coincidence.

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

The idea is to create the pool once and call run() multiple times, which runs the program once on all available threads, and returns afterwards without destroying the threads. The threads then wait for the next run and so on.

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

On windows this worked every time I tried it. On linux however only a single thread starts executing the program and after that nothing happens, so run() never returns.

在Windows上,每次我尝试它都会有效。但是在linux上只有一个线程开始执行程序,之后没有任何反应,所以run()永远不会返回。

I have included a only slightly condensed version of my source code because I thought the thing might be small enough. If someone is interested in taking a look I suspect loop() and wait_all() in the middle of the code section are the most relevant parts. I have also included the declaration as a reference in case the variable types are not clear from name/context.

我已经包含了我的源代码的一个略微浓缩的版本,因为我认为这个东西可能足够小。如果有人有兴趣看看我怀疑代码部分中间的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);
};

1 个解决方案

#1


You are violating the standard's requirements for calling wait:

您违反了标准呼叫等待的要求:

void wait(unique_lock& lock);

void wait(unique_lock&lock);

Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either:

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

— no other thread is waiting on this condition_variable object or

- 没有其他线程在等于这个condition_variable对象或

— lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait or timed_wait) threads.

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

You can have concurrently waiting threads whose lock refers to a different mutex. So you don't meet the prerequisites for calling wait on a condition_variable.

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

I believe you could use a condition_variable_any, which doesn't have this requirement.

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

#1


You are violating the standard's requirements for calling wait:

您违反了标准呼叫等待的要求:

void wait(unique_lock& lock);

void wait(unique_lock&lock);

Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either:

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

— no other thread is waiting on this condition_variable object or

- 没有其他线程在等于这个condition_variable对象或

— lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait or timed_wait) threads.

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

You can have concurrently waiting threads whose lock refers to a different mutex. So you don't meet the prerequisites for calling wait on a condition_variable.

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

I believe you could use a condition_variable_any, which doesn't have this requirement.

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