[英]c++11 shared_ptr using in multi-threads
最近,我正在考慮使用c ++ 11的高性能事件驅動的多線程框架。 它主要考慮了c ++ 11設施,例如std::thread
, std::condition_variable
, std::mutex
, std::shared_ptr
等。 通常,此框架具有三個基本組件:作業,工人和精簡流程,這似乎是一個真正的工廠。 當用戶在服務器端構建其業務模型時,他只需要考慮數據及其處理器。 一旦建立模型,用戶只需要構造數據類繼承的作業和處理器類繼承的工作器。
例如:
class Data : public job {};
class Processsor : public worker {};
服務器獲取數據時,它只是通過數據源回調線程中的auto data = std::make_shared<Data>()
來新建一個Data對象,並調用流線。 job_dispatch
將處理器和數據傳輸到其他線程。 當然,用戶不必考慮釋放內存。 精簡。 job_dispatch
主要做以下事情:
void evd_thread_pool::job_dispatch(std::shared_ptr<evd_thread_job> job) {
auto task = std::make_shared<evd_task_wrap>(job);
task->worker = streamline.worker;
// worker has been registered in streamline first of all
{
std::unique_lock<std::mutex> lck(streamline.mutex);
streamline.task_list.push_back(std::move(task));
}
streamline.cv.notify_all();
}
在evd_task_wrap
使用的job_dispatch
定義為:
struct evd_task_wrap {
std::shared_ptr<evd_thread_job> order;
std::shared_ptr<evd_thread_processor> worker;
evd_task_wrap(std::shared_ptr<evd_thread_job>& o)
:order(o) {}
};
最后,task_wrap將被分派到經過處理線程task_list
這是一個std::list
對象。 並且處理線程主要將事情做為:
void evd_factory_impl::thread_proc() {
std::shared_ptr<evd_task_wrap> wrap = nullptr;
while (true) {
{
std::unique_lock<std::mutex> lck(streamline.mutex);
if (streamline.task_list.empty())
streamline.cv.wait(lck,
[&]()->bool{return !streamline.task_list.empty();});
wrap = std::move(streamline.task_list.front());
streamline.task_list.pop_front();
}
if (-1 == wrap->order->get_type())
break;
wrap->worker->process_task(wrap->order);
wrap.reset();
}
}
但是我不知道為什么該過程經常在thread_proc
函數中崩潰。 並且coredump提示有時換行是空的shared_ptr或段錯誤,發生在wr_reset()中調用的_Sp_counted_ptr_inplace::_M_dispose
中。 我以為在這種情況下shared_ptr存在線程同步問題,而我知道shared_ptr中的控制塊是線程安全的。 當然, job_dispatch
和thread_proc
中的shared_ptr指向相同的存儲,但它們是不同的shared_ptr對象。 是否有人對如何解決此問題有更具體的建議? 或者是否存在使用c ++ 11進行自動內存管理的類似輕量級框架
process_task的示例,例如: void log_handle::process_task(std::shared_ptr<crx::evd_thread_job> job) { auto j = std::dynamic_pointer_cast<log_job>(job); j->log->Printf(0, j->print_str.c_str()); write(STDOUT_FILENO, j->print_str.c_str(), j->print_str.size()); } class log_factory { public: log_factory(const std::string& name); virtual ~log_factory(); void print_ts(const char *format, ...) { //here dispatch the job char log_buf[4096] = {0}; va_list args; va_start(args, format); vsprintf(log_buf, format, args); va_end(args); auto job = std::make_shared<log_job>(log_buf, &m_log); m_log_th.job_dispatch(job); } public: E15_Log m_log; std::shared_ptr<log_handle> m_log_handle; crx::evd_thread_pool m_log_th; };
void log_handle::process_task(std::shared_ptr<crx::evd_thread_job> job) { auto j = std::dynamic_pointer_cast<log_job>(job); j->log->Printf(0, j->print_str.c_str()); write(STDOUT_FILENO, j->print_str.c_str(), j->print_str.size()); } class log_factory { public: log_factory(const std::string& name); virtual ~log_factory(); void print_ts(const char *format, ...) { //here dispatch the job char log_buf[4096] = {0}; va_list args; va_start(args, format); vsprintf(log_buf, format, args); va_end(args); auto job = std::make_shared<log_job>(log_buf, &m_log); m_log_th.job_dispatch(job); } public: E15_Log m_log; std::shared_ptr<log_handle> m_log_handle; crx::evd_thread_pool m_log_th; };
我在您的代碼中檢測到一個問題,該問題可能相關,也可能不相關:
您可以從條件變量中使用notify_all
。 這將喚醒所有線程。 如果將wait
時間包裝在while循環中,則可以,例如:
while (streamline.task_list.empty())
streamline.cv.wait(lck, [&]()->bool{return !streamline.task_list.empty();});
但是由於使用的是if
,因此所有線程都將wait
。 如果您分發一個產品並具有多個消費者線程,則除一個線程外的所有線程都將調用wrap = std::move(streamline.task_list.front());
而任務列表為空並導致UB。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.