在 C 中,您需要在分配給原子之前鎖定互斥鎖嗎?我嘗試實作執行緒池,如此處所示https://stackoverflow.com/a/32593825/2793618。為此,我創建了一個執行緒安全佇列并使用了原子。特別是,在shutdown方法中(或在我的代碼中waitForCompletion)需要將執行緒池回圈函式 while 回圈變數設定為 true,以便執行緒可以完成其作業并加入。但是由于原子是執行緒安全的,所以我在關閉方法中為它分配 true 之前沒有鎖定互斥鎖,如下所示。這最終導致了僵局。為什么會這樣?
執行緒池.hpp:
#pragma once
#include <atomic>
#include <vector>
#include <iostream>
#include <thread>
#include <future>
#include <mutex>
#include <queue>
#include <functional>
#include <ThreadSafeQueue.hpp>
class ThreadPool{
public:
ThreadPool(std::atomic_bool& result);
void waitForCompletion();
void addJob(std::function<bool()> newJob);
void setComplete();
private:
void workLoop(std::atomic_bool& result);
int m_numThreads;
std::vector<std::thread> m_threads;
std::atomic_bool m_workComplete;
std::mutex m_mutex;
std::condition_variable m_jobWaitCondition;
ThreadSafeQueue<std::function<bool()>> m_JobQueue;
};
執行緒池.cpp:
#include <ThreadPool.hpp>
ThreadPool::ThreadPool(std::atomic_bool& result){
m_numThreads = std::thread::hardware_concurrency();
m_workComplete = false;
for (int i = 0; i < m_numThreads; i )
{
m_threads.push_back(std::thread(&ThreadPool::workLoop, this, std::ref(result)));
}
}
// each thread executes this loop
void ThreadPool::workLoop(std::atomic_bool& result){
while(!m_workComplete){
std::function<bool()> currentJob;
bool popped;
{
std::unique_lock<std::mutex> lock(m_mutex);
m_jobWaitCondition.wait(lock, [this](){
return !m_JobQueue.empty() || m_workComplete.load();
});
popped = m_JobQueue.pop(currentJob);
}
if(popped){
result = currentJob() && result;
}
}
}
void ThreadPool::addJob(std::function<bool()> newJob){
m_JobQueue.push(newJob);
m_jobWaitCondition.notify_one();
}
void ThreadPool::setComplete(){
m_workComplete = true;
}
void ThreadPool::waitForCompletion(){
{
std::unique_lock<std::mutex> lock(m_mutex);
m_workComplete.store(true);
}
m_jobWaitCondition.notify_all();
for(auto& thread : m_threads){
thread.join();
}
m_threads.clear();
}
執行緒安全佇列.hpp:
#pragma once
#include <mutex>
#include <queue>
template <class T>
class ThreadSafeQueue {
public:
ThreadSafeQueue(){};
void push(T element) {
std::unique_lock<std::mutex> lock(m_mutex);
m_queue.push(element);
}
bool pop(T& retElement) {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_queue.empty()) {
return false;
}
retElement = m_queue.front();
m_queue.pop();
return true;
}
bool empty(){
std::unique_lock<std::mutex> lock(m_mutex);
return m_queue.empty();
}
private:
std::queue<T> m_queue;
std::mutex m_mutex;
};
uj5u.com熱心網友回復:
在等待條件時,您有死鎖。雖然僅在添加新作業時才會通知該條件。您的執行緒正在等待通知該條件。您可能對條件“條件”進行非確定性(從您的角度來看)檢查,但您可能不依賴它們的存在。
您需要在任務完成時通知您的情況。一個可能的地方是當您呼叫等待完成時或可以達到完成狀態的任何時間點。
我將您的代碼更改為此以說明:
// each thread executes this loop
void ThreadPool::workLoop(std::atomic_bool& result){
while(!m_workComplete)
{
std::function<bool()> currentJob;
bool popped;
{
std::cout<<"Before the lock"<<std::endl;
std::unique_lock<std::mutex> lock(m_mutex);
std::cout<<"After lock"<<std::endl;
m_jobWaitCondition.wait(lock, [this]()
{
bool res = (!m_JobQueue.empty() || m_workComplete.load() );
std::cout<<"res:"<<res<<std::endl;
return res;
});
std::cout<<"After wait"<<std::endl;
popped = m_JobQueue.pop(currentJob);
}
if(popped)
{
std::cout<<"Popped"<<std::endl;
result = currentJob() && result;
std::cout<<"Popped 2"<<std::endl;
}
}
std::cout<<"LEave"<<std::endl;
}
void ThreadPool::addJob(std::function<bool()> newJob){
m_JobQueue.push(newJob);
std::cout<<"before call notify"<<std::endl;
m_jobWaitCondition.notify_one();
std::cout<<"After call notify"<<std::endl;
}
我添加了一個作業,列印的內容是:
加鎖前 加鎖后 res:0 加鎖前 加鎖后 加鎖前 加鎖前 加鎖前 res:0 加鎖前 加鎖后 res:0 加鎖后 res:0 加鎖前 加鎖后 res:0 加鎖后呼叫前通知:1
鎖定前等待后
Popped After lock res:0 After call notifyres:0
Popped 2 Before the lock res:0 res:0 res:0 res:0 After lock
res:0
After lock
res:0
Notice that last notify is called BEFORE the last "after lock" line (that precedes the condition wait)
uj5u.com熱心網友回復:
您可能希望在 workLoop() 中的 wait() 回傳后檢查 m_workComplete,否則您可能會在空佇列上呼叫 pop(),這很糟糕。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/452680.html
