C ++ condition_variable互斥锁定问题

时间:2016-03-11 00:36:31

标签: c++ multithreading

我需要使用std :: condition_variable来实现我的多线程目的,但它需要一个对我来说很大的负面锁定。在我刚刚创建新线程但创建新线程并花费太多时间之前。所以我查看条件变量,但它锁定了该函数,因此只有线程可以一次执行它。我会创建许多ExecutionWorker()副本,并将它们重命名为ExecutionWorker1(),ExecutionWorker2(),ExecutionWorker3(),ExecutionWorker4()......等等。然后为每个函数创建新线程并使用条件变量,如果我为每个函数副本使用不同的互斥锁,它将使其有效锁定,但我不想这样做太乱。

任何人都有什么想法我能做什么?我需要多个线程一次从execVec队列执行。在目前使用条件变量和互斥体loc的情况下,execVec中的一些函数将具有Sleep(),因此只有在完成所有操作之后,当另一个线程有效地执行作业时,互斥锁才会被解锁并再次锁定只执行一个线程一次

std::mutex mu;
std::condition_variable condition;
std::vector<void(__cdecl*)()> execVec;

void ExecutionWorker()
{
    while(true)
    {
        std::unique_lock<std::mutex> locker(mu);
        p_IScript->condition.wait(locker, []() -> bool { return execVec.size() > 0; });

        // execute  a member of execVec here
        // imagine it takes 5 seconds so Sleep(5000) will replace that code

        execItem();

        Sleep(5000);
    }
}

3 个答案:

答案 0 :(得分:0)

您可以在锁定下制作execVec元素的副本,然后在没有锁定的情况下执行它,按照以下方式执行:

while(true)
{
    decltype(execVec)::value_type execItem;

    {
        std::unique_lock<std::mutex> locker(mu);
        p_IScript->condition.wait(locker, []() -> bool { return execVec.size() > 0; });
        execItem = execVec.back();
        execVec.pop_back();
    }

    // This code is executed outside the lock scope,
    // so it doesn't affect the execution of other threads.
    Sleep(5000);
}

答案 1 :(得分:0)

您只需要在向量推送和弹出时锁定。执行锁定范围外的功能。例如:

#include <condition_variable>
#include <functional>
#include <mutex>
#include <queue>

class task_queue
{
public:
    using task = std::function<void ()>;

private:
    std::mutex m;
    std::condition_variable cv;
    std::queue<task> tasks;

public:
    void push_task(task t)
    {
        {
            std::lock_guard<std::mutex> lock(m);
            tasks.push(t);
        }

        cv.notify_one();
    }

    void process_tasks()
    {
        while (true)
        {
            task t;

            {
                std::unique_lock<std::mutex> lock(m);
                cv.wait(lock, [this]() { return !tasks.empty(); });
                t = tasks.back();
                tasks.pop();
            }

            t();
        }
    }
};

答案 2 :(得分:0)

谢谢大家的帮助。

这很简单,因为大家都建议我只需要在另一个范围内使用unique_lock,这样当它执行时它会再次解锁。

这是最终解决方案自给自足的可编译代码,我应该在首发帖子中发布..

std::condition_variable cond;
std::mutex mu;
std::queue<void(__cdecl*)()> execQueue;

typedef void (__cdecl* callback)();

callback RequestAcces(scrQueueReqType type, callback func = nullptr)
{
    MUTEX_LOCK_GUARD;
    if(type == QUEUE_ADDJOB)
    {
        execQueue.push(func);
        return nullptr;
    }
    else
    {
        callback retfunc = execQueue.front();
        execQueue.pop();
        return retfunc;
    }
}

void Worker()
{
    while(true)
    {
        {
            std::unique_lock<std::mutex> locker(mu);
            cond.wait(locker, []() -> bool {return !execQueue.empty();} );
        }

        callback to_exec = RequestAcces(QUEUE_GETJOB);
        to_exec();
    }
}

void main()
{
    std::thread t1(Worker);
    std::thread t2(Worker);
    std::thread t3(Worker);

    t1.detach();
    t2.detach();
    t3.detach();

    while(true)
    {
        auto func = []()
        {
            printf("This job was completed by threadId: 0x%X\n", GetCurrentThreadId());
            Sleep(3000);
        };

        RequestAcces(QUEUE_ADDJOB, func);
        cond.notify_one();
        Sleep(50);
    }
}