如果线程对象声明为成员

时间:2015-11-29 15:23:09

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

我写了一个名为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会话,但这里并不相关。 一切正常,线程开始并成功发布事件,直到工作结束。 这是一个工作片段:

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

这是Restore类:

        class Restore : public Task {

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

            virtual void run();

        private:
            ... stuffs ...
        };

现在我试图在N subTasks(Worker,也是Task的子类)中拆分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类运行方法时创建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);
            }

我更喜欢在没有新操作符的情况下创建Worker,因为在Restore :: run()完成之后我真的不需要保持这些对象的活着,我应该能够保证这些对象仍然存在由于线程连接(已通过调试器验证),子项完成之前一直存在。

谁能在这里找到瓶颈?

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

最好的问候

1 个答案:

答案 0 :(得分:0)

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

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

您也可以创建一个Worker数组而不是for循环, 在这种情况下,你必须使用默认的ctor,并以其他方式传递初始化器(this,start)