【问题标题】:Boost Thread start failure if thread object declared as member如果线程对象声明为成员,则提升线程启动失败
【发布时间】:2015-11-29 15:23:09
【问题描述】:

我编写了一个名为 Task 的类,它封装了一个 boost::thread 并允许重写 run() 方法以在新创建的线程上做一些工作。

这是基类:

class Task {


    typedef boost::function<void ()> TaskEventCallback;
    typedef boost::unordered_map<string, TaskEventCallback> Callbacks;
    typedef boost::unordered_map<string, Callbacks> SessionTaskMap;
    typedef boost::unordered_map<TaskListener *, SessionTaskMap> ListenersMap;

    public:
        Task(NGSAppServer& server);
        Task(const Task& orig);
        virtual ~Task();

        virtual void run() = 0;
        bool start();
        bool pause();
        bool cancel();

        virtual bool registerListener(TaskListener *);
        virtual bool unregisterListener(TaskListener *);
        string getProgress();
        string getStatusMessage();

        boost::thread * getThread();

    protected:
        void postEvent(string event);
        void startThread();

        void setProgress(string progress);
        void setStatusMessage(string statusMessage);


        vector<TaskListener *> listeners;
        bool taskRunning;
        bool taskStarted;
        bool taskCanceled;
        bool taskEnded;
        NGSAppServer& server;

        boost::thread worker;
        boost::recursive_mutex mutex;

        ListenersMap listeners_map;

    private:
        string progress;
        string statusMessage;

};

该类能够通过服务器类将事件发布到多个 http 会话,但在这里不相关。 一切正常,线程启动并成功发布事件,直到工作结束。 这是一个有效的 sn-p:

        RestoreTask * task = new RestoreTask(application->getServer());
        TaskListener * listener = new TmpTL(*task, progressText, this);
        task->start();

这是恢复类:

        class Restore : public Task {

        public:
            Restore(NGSAppServer& server);
            Restore(const Restore& orig);
            virtual ~Restore();

            virtual void run();

        private:
            ... stuffs ...
        };

现在我尝试将还原任务的工作拆分为 N 个子任务(Worker,也是任务的子类)。 这里是新的Restore运行方法:

            std::vector<Worker *> workers;
            for(uint i = 0; i < 2; i++){
                //Start tread
                Worker _worker(this, server);
                _worker.start();
                workers.push_back(&_worker);
            }

            //Join Workers
            for(uint i = 0; i < 2; i++){
                workers.at(i)->getThread()->join();
            }

此代码失败,因为子线程的启动在尝试运行 Worker 类的 run 方法时创建了一个 sigfault,因为它被报告为纯虚拟,而且尝试锁定 Task 基类上的互斥锁在此断言上失败:

void boost::recursive_mutex::lock(): Assertion `!pthread_mutex_lock(&m)' failed.

直接创建一个 Worker 对象并启动它(对于恢复)不会产生任何问题!

乍一看,Restore run() 方法可能会在子线程之前结束,删除 Worker 实例,然后在运行时调用基类(纯虚拟)并尝试访问已破坏的互斥锁。 (如果我在这里错了,请纠正我!)

使用调试器深入了解我发现的问题并非如此。 问题似乎停留在 Worker 对象声明中,因为以下更改使代码可以正常工作:

            std::vector<Worker *> workers;
            for(uint i = 0; i < 2; i++){
                //Start tread
                Worker * _worker = new Worker(this, server);
                _worker->start();
                workers.push_back(_worker);
            }

            for(uint i = 0; i < 2; i++){
                workers.at(i)->getThread()->join();
                delete workers.at(i);
            }

我更喜欢在没有 new 运算符的情况下创建 Workers,因为在 Restore::run() 完成后我真的不需要让这些对象保持活动状态,并且我应该能够保证这些对象仍然存在,直到孩子完成由于线程连接(已通过调试器验证)。

谁能找到这里的瓶颈?

我已经能够找到一种方法来运行我的代码,但仍然缺少解决方案(但对我来说更重要的是这里的解释)。

最好的问候

【问题讨论】:

    标签: c++ multithreading boost pure-virtual boost-mutex


    【解决方案1】:

    当 for 循环重复时,_worker 将超出范围并被破坏。 您可以在析构函数中打印以验证这一点。

    您在第二个(新的 ..delete)中所做的事情是正确的, 也许您可以使用 smart_ptr / make_ptr 来避免删除。

    你也可以创建一个 Workers 数组来代替 for 循环, 在这种情况下,您必须使用默认 ctor,并以其他方式传递初始化程序( this、start )

    【讨论】:

    • 简单明了!我在寻找一只蚂蚁的同时也在寻找一座山!像白痴一样快乐,我现在可以睡觉了:)非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2018-03-29
    • 1970-01-01
    • 1970-01-01
    • 2016-02-23
    • 1970-01-01
    • 2011-01-07
    • 2013-09-21
    • 2012-05-27
    相关资源
    最近更新 更多