簡體   English   中英

在多線程中使用的c ++ 11 shared_ptr

[英]c++11 shared_ptr using in multi-threads

最近,我正在考慮使用c ++ 11的高性能事件驅動的多線程框架。 它主要考慮了c ++ 11設施,例如std::threadstd::condition_variablestd::mutexstd::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_dispatchthread_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM