C++ 无法将元素添加到共享指针的线程安全锁定队列
我正在尝试使用C++11并发技术创建一个基于线程间消息的通信。Anthony William的书《动作中的并发》(Concurrency in Action)描述了此实现所基于的线程安全锁定队列。书中描述的线程安全锁定队列与我想要实现的线程安全锁定队列之间的区别在于,首先,我使用通用引用将队列元素转发到阻塞队列,其次(这就是问题所在)我需要能够存储std::shared_ptr指针队列,因为模板类型由一个简单的消息类层次结构(带有抽象基类)和带有实际专门消息的子类组成。我需要使用共享指针来避免数据切片 编辑:我添加了一个coliru演示,以更清楚地显示我的问题。 编辑1:对coliru live演示的更多更新以及其他编译器错误: 编辑2:多亏了亚历杭德罗,我有了一个有效的解决方案 为此,我将Anthony William对底层消息队列的实现更改为:C++ 无法将元素添加到共享指针的线程安全锁定队列,c++,multithreading,c++11,ipc,shared-ptr,C++,Multithreading,C++11,Ipc,Shared Ptr,我正在尝试使用C++11并发技术创建一个基于线程间消息的通信。Anthony William的书《动作中的并发》(Concurrency in Action)描述了此实现所基于的线程安全锁定队列。书中描述的线程安全锁定队列与我想要实现的线程安全锁定队列之间的区别在于,首先,我使用通用引用将队列元素转发到阻塞队列,其次(这就是问题所在)我需要能够存储std::shared_ptr指针队列,因为模板类型由一个简单的消息类层次结构(带有抽象基类)和带有实际专门消息的子类组成。我需要使用共享指针来避免数
std::queue<T> data_queue
std::队列数据\u队列
到
std::队列数据\u队列
但是,当我试图通过universal reference perfect forwarding签名在队列上推送消息指针时,会出现各种错误
我希望能够在此队列上添加消息的方式如下:
UtlThreadSafeQueue<BaseMessageType>& mDataLoadSessionQ;
auto message = std::make_shared<DerivedType>(1,2,3);
mDataLoadSessionQ.push(BaseType);
/*
** code adapted from Anthony Williams's book C++ Concurrency in Action
** Pages 74-75.
**
*/
#ifndef _utlThreadSafeQueue_h_
#define _utlThreadSafeQueue_h_
// SYSTEM INCLUDES
#include <atomic>
#include <queue>
#include <limits>
#include <memory>
#include <mutex>
#include <condition_variable>
// APPLICATION INCLUDES
// MACROS
#if defined (_WIN32) && (defined (max) || defined (min))
// Windows uses min/max macros
#undef min
#undef max
#endif
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
template<typename T>
class UtlThreadSafeQueue {
private:
mutable std::mutex mut;
std::queue<std::shared_ptr<T>> data_queue;
std::condition_variable data_cond;
std::size_t capacity;
std::atomic<bool> shutdownFlag;
public:
explicit UtlThreadSafeQueue(const size_t& rCapacity =
std::numeric_limits<std::size_t>::max())
: mut()
, data_queue()
, data_cond()
, capacity(rCapacity)
, shutdownFlag(false)
{}
UtlThreadSafeQueue(UtlThreadSafeQueue const& rhs) {
std::lock_guard<std::mutex> lock(rhs.mut);
data_queue = rhs.data_queue;
}
virtual ~UtlThreadSafeQueue() = default;
// move aware push
inline void push(T&& value) {
std::unique_lock<std::mutex> lock(mut);
// only add the value on the stack if there is room
data_cond.wait(lock,[this]{return (data_queue.size() < capacity) || shutdownFlag;});
data_queue.emplace(std::forward<T>(value));
data_cond.notify_one();
}
// wait for non empty lambda condition before returning value
inline void wait_and_pop(T& rValue) {
std::unique_lock<std::mutex> lock(mut);
data_cond.wait(lock,[this]{return !data_queue.empty();});
// ideally should return an invalid value
if (!shutdownFlag) {
rValue = data_queue.front();
data_queue.pop();
}
}
// wait for non empty lambda condition before returning shared pointer to value
inline std::shared_ptr<T> wait_and_pop() {
std::unique_lock<std::mutex> lock(mut);
data_cond.wait(lock,[this]{return !data_queue.empty() || shutdownFlag;});
if (shutdownFlag) {
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
return nullptr;
}
// return value in specified reference and flag indicating whether value
// successfully returned or not
inline bool try_pop(T& rValue) {
std::lock_guard<std::mutex> lock(mut);
if (data_queue.empty()) {
return false;
}
rValue = data_queue.front();
data_queue.pop();
return true;
}
// return shared pointer to value - which if set to nullptr,
// indicates container was empty at the time of the call.
inline std::shared_ptr<T> try_pop() {
std::lock_guard<std::mutex> lock(mut);
if (data_queue.empty()) {
return std::shared_ptr<T>();
}
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
// thread safe method to check if the queue is empty
// note that if it is empty
inline bool empty() const {
std::lock_guard<std::mutex> lock(mut);
return data_queue.empty();
}
// shutdown support - wake up potentially sleeping queues
inline void shutdown() {
shutdownFlag = true;
data_cond.notify_all();
}
};
#endif // _utlThreadSafeQueue_h_
UtlThreadSafeQueue&mDataLoadSessionQ;
自动消息=标准::使_共享(1,2,3);
mDataLoadSessionQ.push(BaseType);
在上面的代码中,编译器抱怨指出了一些问题
以下行显示错误C2664:“void”
UtlThreadSafeQueue::push(T&)':无法转换
参数1从'std::shared_ptr'到
带有T=BaseMessageType的“BaseMessageType&&”
我想我需要一些专门化指针类型的方法,但我不确定
我的执行情况如下:
UtlThreadSafeQueue<BaseMessageType>& mDataLoadSessionQ;
auto message = std::make_shared<DerivedType>(1,2,3);
mDataLoadSessionQ.push(BaseType);
/*
** code adapted from Anthony Williams's book C++ Concurrency in Action
** Pages 74-75.
**
*/
#ifndef _utlThreadSafeQueue_h_
#define _utlThreadSafeQueue_h_
// SYSTEM INCLUDES
#include <atomic>
#include <queue>
#include <limits>
#include <memory>
#include <mutex>
#include <condition_variable>
// APPLICATION INCLUDES
// MACROS
#if defined (_WIN32) && (defined (max) || defined (min))
// Windows uses min/max macros
#undef min
#undef max
#endif
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
template<typename T>
class UtlThreadSafeQueue {
private:
mutable std::mutex mut;
std::queue<std::shared_ptr<T>> data_queue;
std::condition_variable data_cond;
std::size_t capacity;
std::atomic<bool> shutdownFlag;
public:
explicit UtlThreadSafeQueue(const size_t& rCapacity =
std::numeric_limits<std::size_t>::max())
: mut()
, data_queue()
, data_cond()
, capacity(rCapacity)
, shutdownFlag(false)
{}
UtlThreadSafeQueue(UtlThreadSafeQueue const& rhs) {
std::lock_guard<std::mutex> lock(rhs.mut);
data_queue = rhs.data_queue;
}
virtual ~UtlThreadSafeQueue() = default;
// move aware push
inline void push(T&& value) {
std::unique_lock<std::mutex> lock(mut);
// only add the value on the stack if there is room
data_cond.wait(lock,[this]{return (data_queue.size() < capacity) || shutdownFlag;});
data_queue.emplace(std::forward<T>(value));
data_cond.notify_one();
}
// wait for non empty lambda condition before returning value
inline void wait_and_pop(T& rValue) {
std::unique_lock<std::mutex> lock(mut);
data_cond.wait(lock,[this]{return !data_queue.empty();});
// ideally should return an invalid value
if (!shutdownFlag) {
rValue = data_queue.front();
data_queue.pop();
}
}
// wait for non empty lambda condition before returning shared pointer to value
inline std::shared_ptr<T> wait_and_pop() {
std::unique_lock<std::mutex> lock(mut);
data_cond.wait(lock,[this]{return !data_queue.empty() || shutdownFlag;});
if (shutdownFlag) {
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
return nullptr;
}
// return value in specified reference and flag indicating whether value
// successfully returned or not
inline bool try_pop(T& rValue) {
std::lock_guard<std::mutex> lock(mut);
if (data_queue.empty()) {
return false;
}
rValue = data_queue.front();
data_queue.pop();
return true;
}
// return shared pointer to value - which if set to nullptr,
// indicates container was empty at the time of the call.
inline std::shared_ptr<T> try_pop() {
std::lock_guard<std::mutex> lock(mut);
if (data_queue.empty()) {
return std::shared_ptr<T>();
}
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
// thread safe method to check if the queue is empty
// note that if it is empty
inline bool empty() const {
std::lock_guard<std::mutex> lock(mut);
return data_queue.empty();
}
// shutdown support - wake up potentially sleeping queues
inline void shutdown() {
shutdownFlag = true;
data_cond.notify_all();
}
};
#endif // _utlThreadSafeQueue_h_
/*
**代码,改编自Anthony Williams的书中的C++并发操作
**第74-75页。
**
*/
#ifndef\u utlThreadSafeQueue\u h_
#定义_utlThreadSafeQueue_h_
//系统包括
#包括
#包括
#包括
#包括
#包括
#包括
//应用程序包括
//宏
#如果已定义(_WIN32)和&(已定义(最大)| |已定义(最小))
//Windows使用最小/最大宏
#未定义最小值
#未定义最大值
#恩迪夫
//外部功能
//外部变量
//常数
//结构
模板
类UtlThreadSafeQueue{
私人:
可变std::互斥mut;
std::队列数据\队列;
std::条件变量数据条件;
标准:尺寸和容量;
std::原子关闭标志;
公众:
显式UtlThreadSafeQueue(常量大小和容量)=
标准::数值限制::最大值()
:mut()
,数据队列()
,data_cond()
,容量(R容量)
,shutdowngflag(false)
{}
UTLTREADSAFEQUEUE(UTLTREADSAFEQUEUE常量和rhs){
标准:锁和防护锁(rhs.mut);
data_queue=rhs.data_queue;
}
virtual~UtlThreadSafeQueue()=默认值;
//移动感知推送
内联无效推送(T&&value){
std::唯一锁定(mut);
//仅当有空间时才在堆栈上添加值
data_cond.wait(lock,[this]{return(data_queue.size()
在评论中展开讨论之后,根据Coliru链接,我想我理解您最初的意图,我也想对您的数据结构提出一些建议
- 您提到您的
函数是移动感知的。杰出的但是,要小心 如果您看看如何定义push()
函数push
这里有几件事我想指出。首先,这将只绑定到r值引用,而不是通用引用(或者,很快就会被称为)。你使用inline void push(T&& value)
template<typename U> inline std::enable_if_t<std::is_base_of<T,std::decay_t<U>>::value> push(U&& value) { std::unique_lock<std::mutex> lock(mut); // only add the value on the stack if there is room data_cond.wait(lock,[this]{return (data_queue.size() < capacity) || shutdownFlag;}); data_queue.emplace(std::make_shared<std::decay_t<U>> (std::forward<U>(value))); data_cond.notify_one(); }
UtlThreadSafeQueue<BaseMessage> dataLoadSessionQ(10); StringMessage sm("Hi there!"); IntegerMessage im(4242); dataLoadSessionQ.push(sm); dataLoadSessionQ.push(im);
UtlThreadSafeQueue<BaseMessage> dataLoadSessionQ; auto my_message = std::make_shared<StringMessage>("Another message!"); dataLoadSessionQ.push(my_message);
template< class T, class U > std::shared_ptr<T> static_pointer_cast( const std::shared_ptr<U>& r );
UtlThreadSafeQueue<BaseMessage> dataLoadSessionQ; auto generic_message = std::make_shared<BaseMessage>(); dataLoadSessionQ.push(generic_message);