我需要使用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);
}
}
答案 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);
}
}