Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在C++;_C++_Pthreads_Threadpool_Boost Bind_Boost Function - Fatal编程技术网

C++ 如何在C++;

C++ 如何在C++;,c++,pthreads,threadpool,boost-bind,boost-function,C++,Pthreads,Threadpool,Boost Bind,Boost Function,我尝试用pTr++实现C++中的线程池。我想将与线程管理相关的逻辑封装在一个对象中,该对象拥有这些线程的所有权。这意味着无论何时销毁此对象,都必须停止并清理线程 停止和销毁线程的最佳方法是什么?开始时分离和停止时取消是一个好的解决方案吗?或者最好取消并加入线程?请参阅我的代码,如有任何相关评论,我将不胜感激 WorkerThreadManager.h: #include "WorkerThreadManagerInterface.h" #include "utils/mutex.h" #incl

我尝试用pTr++实现C++中的线程池。我想将与线程管理相关的逻辑封装在一个对象中,该对象拥有这些线程的所有权。这意味着无论何时销毁此对象,都必须停止并清理线程

停止和销毁线程的最佳方法是什么?开始时分离和停止时取消是一个好的解决方案吗?或者最好取消并加入线程?请参阅我的代码,如有任何相关评论,我将不胜感激

WorkerThreadManager.h:

#include "WorkerThreadManagerInterface.h"
#include "utils/mutex.h"
#include <queue>
#include <semaphore.h>

#include <iostream>

class WorkerThreadManager : public WorkerThreadManagerInterface
{
    public:
        WorkerThreadManager(unsigned threadsNumber = 5);
        virtual ~WorkerThreadManager();

        virtual void    PushTask(thread_function_t A_threadFun, result_function_t A_resultFun);
        void    SignalResults();

    private:
        static void*    WorkerThread(void* A_data);

        void    PushResult(int A_result, result_function_t A_resultFun);

        typedef boost::function<void ()> signal_function_t;

        struct worker_thread_data_t
        {
            worker_thread_data_t(thread_function_t A_threadFun, result_function_t A_resultFun) :
                threadFun(A_threadFun), resultFun(A_resultFun) {}
            worker_thread_data_t() {}

            thread_function_t       threadFun;
            result_function_t       resultFun;
        };


        const unsigned                      m_threadsNumber;
        pthread_t*                          m_pthreads;

        utils::Mutex                        m_tasksMutex;
        sem_t                               m_tasksSem;
        std::queue<worker_thread_data_t>    m_tasks;

        utils::Mutex                        m_resultsMutex;
        std::queue<signal_function_t>       m_results;
};
#包括“WorkerThreadManagerInterface.h”
#包括“utils/mutex.h”
#包括
#包括
#包括
类WorkerThreadManager:公共WorkerThreadManager接口
{
公众:
WorkerThreadManager(无符号threadsNumber=5);
虚拟~WorkerThreadManager();
虚拟任务(线程函数、结果函数、结果函数);
void SignalResults();
私人:
静态void*WorkerThread(void*A_数据);
void PushResult(int A_result、result函数t A_resultFun);
typedef boost::功能信号\u功能\u t;
结构工作线程数据
{
辅助线程数据(线程函数、结果函数、结果函数):
threadFun(A_threadFun),resultFun(A_resultFun){}
辅助线程数据({}
thread_函数\u t threadFun;
结果函数结果函数;
};
常量无符号m_threadsNumber;
pthread_t*m_pthreads;
utils::互斥m_tasksMutex;
sem_t m_tasksem;
std::队列m_任务;
utils::Mutex m_resultsMutex;
std::队列m_结果;
};
WorkerThreadManager.cpp:

#include "WorkerThreadManager.h"
#include "gateway_log.h"
#include <pthread.h>

/**
 * @brief Creates semaphore and starts threads.
 */
WorkerThreadManager::WorkerThreadManager(unsigned threadsNumber) : m_threadsNumber(threadsNumber)
{
    if ( sem_init(&m_tasksSem, 0, 0) )
    {
        std::stringstream ss;
        ss << "Semaphore could not be initialized: " << errno << " - " << strerror(errno);
        LOG_FATAL(ss);
        throw std::runtime_error(ss.str());
    }

    m_pthreads = new pthread_t[m_threadsNumber];
    for (unsigned i = 0; i < m_threadsNumber; ++i)
    {
        int rc = pthread_create(&m_pthreads[i], NULL, WorkerThreadManager::WorkerThread, (void*) this );
        if(rc)
        {
            std::stringstream ss;
            ss << "Pthread could not be started: " << errno << " - " << strerror(errno);
            LOG_FATAL(ss.str());

            if ( sem_destroy(&m_tasksSem) )
                LOG_ERROR("Semaphore could not be destroyed: " << errno << " - " << strerror(errno));

            delete [] m_pthreads;

            throw std::runtime_error(ss.str());
        }
        else
        {
            LOG_DEBUG("Worker thread started " << m_pthreads[i]);

            if(pthread_detach(m_pthreads[i]))
                LOG_WARN("Failed to detach worker thread");
        }
    }
}

/**
 * @brief Cancels all threads, destroys semaphore
 */
WorkerThreadManager::~WorkerThreadManager()
{
    LOG_DEBUG("~WorkerThreadManager()");

    for(unsigned i = 0; i < m_threadsNumber; ++i)
    {
        if ( pthread_cancel(m_pthreads[i]) )
            LOG_ERROR("Worker thread cancellation failed");
    }

    if ( sem_destroy(&m_tasksSem) )
        LOG_ERROR("Semaphore could not be destroyed: " << errno << " - " << strerror(errno));

    delete [] m_pthreads;
}

/**
 * @brief Adds new task to queue, so worker threads can
 * @param A_threadFun function which will be executed by thread
 * @param A_resultFun function which will be enqueued for calling with return value of A_threadFun as parameter
 *          after worker thread executes A_threadFun.
 */
void WorkerThreadManager::PushTask(thread_function_t A_threadFun, result_function_t A_resultFun)
{
    utils::ScopedLock mutex(m_tasksMutex);

    worker_thread_data_t    data(A_threadFun, A_resultFun);
    m_tasks.push( data );
    sem_post(&m_tasksSem);
    LOG_DEBUG("Task for worker threads has been added to queue");
}

/**
 * @brief   Executes result functions (if there are any) to give feedback 
 *  to classes which requested task execution in worker thread.
 */
void WorkerThreadManager::SignalResults()
{
    while(true)
    {
        signal_function_t signal;
        {
            utils::ScopedLock mutex(m_resultsMutex);
            if(m_results.size())
            {
                signal = m_results.front();
                m_results.pop();
            }
            else
                return;
        }

        signal();
    }
}

/**
 * @brief Enqueues result of function executed in worker thread.
 * @param A_result return value of function executed in worker thread
 * @param A_resultFun function which will be enqueued for calling with A_result as a parameter.
 */
void WorkerThreadManager::PushResult(int A_result, result_function_t A_resultFun)
{
    utils::ScopedLock mutex(m_resultsMutex);

    signal_function_t signal = boost::bind(A_resultFun, A_result);
    m_results.push( signal );
}


/**
 * @brief   worker thread body
 * @param A_data pointer to WorkerThreadManager instance
 */
void* WorkerThreadManager::WorkerThread(void* A_data)
{
    WorkerThreadManager* manager = reinterpret_cast<WorkerThreadManager*>(A_data);
    LOG_DEBUG("Starting worker thread loop");
    while (1)
    {
        if ( -1 == sem_wait(&manager->m_tasksSem) && errno == EINTR )
        {
            LOG_DEBUG("sem_wait interrupted with signal");
            continue;
        }
        LOG_DEBUG("WorkerThread:::::: about to call lock mutex");

        worker_thread_data_t data;
        {
            utils::ScopedLock mutex(manager->m_tasksMutex);
            data = manager->m_tasks.front();
            manager->m_results.pop();
        }

        LOG_DEBUG("WorkerThread:::::: about to call resultFun");
        int result  = data.threadFun();
        LOG_DEBUG("WorkerThread:::::: after call resultFun");
        pthread_testcancel();

        manager->PushResult(result, data.resultFun);
    }

    return NULL;
}
#包括“WorkerThreadManager.h”
#包括“gateway_log.h”
#包括
/**
*@brief创建信号量并启动线程。
*/
WorkerThreadManager::WorkerThreadManager(未签名线程数):m_threadsNumber(线程数)
{
if(sem_init(&m_tasksSem,0,0))
{
std::stringstream-ss;

ss关于安全停止:我更喜欢
pthread\u join
。我不使用
pthread\u cancel
-我使用特殊的停止消息,但我总是使用事件驱动的线程(指带有一些消息队列的线程)。当线程获得
退出消息时,它停止循环,然后join返回到我的
代码


关于您的代码-我建议创建
类线程
封装单个线程。池应该在堆上创建
线程
对象-就像现在您有
pthread\u t
数组一样。如果您需要池和线程之间的同步,那么您不能在不确定
线程对象被销毁。

作为一个观点:<代码> pthRead取消/<代码>是魔鬼:它结束时更难控制终止,或者可能或可能不很好地与C++(取决于实现)进行交互。关闭线程池的一部分的最佳方法是排队“死亡任务”。。当线程从队列中提取作业时,它会检查该作业是否为“死亡作业”,如果是,则自行终止。哦,是的,在自动初始化中,我错过了“新WorkerThreadManager”,我很抱歉。当我试图准备这篇文章时,我复制并粘贴了我的应用程序中的代码。我还从一些测试代码中清理了示例,因此您在backtrace中看到的行号可能与粘贴的代码中的行号不完全相同。从StackOverflow礼节的角度来看,我认为最好将两个问题作为两个单独的问题来问,然后人们可以清楚地知道他们在回答哪个问题,你可以为每个问题接受一个答案。@Bryan我将问题分开,所以这个问题与线程池清理有关,与崩溃有关。当我想加入工作线程时,我应该如何唤醒工作线程?最简单的解决方案,但可能不是最好的方法是调用
post\sem
对每个工作线程执行一次。您可以添加一些标志
exitThread
-将其设置为
true
,然后根据要停止的线程的次数发布信号量。但这只是快速查看后的一个好建议,不要太认真;)
#include "gateway_log.h"
#include "WorkerThreadManager.h"
#include <memory>

class A {
public:
    int Fun() { LOG_DEBUG("Fun before sleep"); sleep(8); LOG_DEBUG("Fun after sleep");return 0; }
    void Result(int a) { LOG_DEBUG("Result: " << a); }
};


int main()
{
    sd::auto_ptr<WorkerThreadManager> workerThreadManager = new WorkerThreadManager;
    A a;
    workerThreadManager->PushTask(boost::bind(&A::Fun, &a), boost::bind(&A::Result, &a, _1));
    sleep(3);
    LOG_DEBUG("deleting workerThreadManager");
    workerThreadManager.reset();                    // <<<--- CRASH
    LOG_DEBUG("deleted workerThreadManager");
    sleep(10);
    LOG_DEBUG("after sleep");    

    return 0;
}