Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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++_Multithreading - Fatal编程技术网

C++ 线程包装器实现问题

C++ 线程包装器实现问题,c++,multithreading,C++,Multithreading,我正在围绕win32线程和pthread编写一个包装类,其风格类似于c++11线程api。 我的问题是当线程对象实例的实际线程已经退出时更新它。下面是一个解决方案,我有,但我不知道它是否安全 /* Thread wrapper class */ class Thread { public: enum ThreadState { DETACHED = 0, RUNNING };

我正在围绕win32线程和pthread编写一个包装类,其风格类似于c++11线程api。 我的问题是当线程对象实例的实际线程已经退出时更新它。下面是一个解决方案,我有,但我不知道它是否安全

/* Thread wrapper class */
    class Thread
    {
    public:
        enum ThreadState
        {
            DETACHED = 0,
            RUNNING
        };

        Thread();
        Thread(void* (*start) (void*), void* arg);
        ~Thread();

        Thread& operator=(Thread& other);
        void Join();
        int32_t SetPriority(int32_t priority);
        void Detach();
        ThreadHandle GetNativeHandle();
        ThreadState GetThreadState();

    private:
        ThreadHandle mHandle;
        ThreadState mState;
        void* (*mFunctionPointer) (void*);
        void* mArg;

        static void* Run(void* arg);
        ThreadHandle _CreateThread(void* (*start) (void*), void* arg);
        void _JoinThread(ThreadHandle& handle);

    };
第二个构造函数启动一个线程。以下是实现:

    Thread::Thread(void* (*start) (void*), void* arg)
    {
        mFunctionPointer = start;
        mArg = arg;
        mState = Thread::RUNNING;

        mHandle = _CreateThread(&Run, (void*)this);
        if (!mHandle)
            mState = Thread::DETACHED;
    }
它创建一个线程,该线程运行Run方法并传递指向此对象实例的指针。原因是一旦线程执行了函数,它就会将状态设置为DETACHED,以表示它已完成

下面是Run方法

    void* Thread::Run(void* arg)
    {
        Thread* thread = static_cast<Thread*>(arg);

        if (thread && thread->mFunctionPointer && thread->mArg && thread->mState == Thread::RUNNING)
            thread->mFunctionPointer(thread->mArg);

        if (thread && thread->mFunctionPointer && thread->mArg && thread->mState == Thread::RUNNING)
            thread->Detach();

        return NULL;
    }
我觉得这根本不安全。例如,如果线程对象是在堆栈上构造的,并且在其线程运行时超出范围。线程对象析构函数使其状态和数据成员为空,但内存位置可能被覆盖否

有什么好办法解决这个问题吗


谢谢

如果线程实例超出范围而之前没有加入线程,那么您就注定要失败。将Run()设为自由函数或静态函数,并将函数需要运行的所有数据复制到动态分配的内存中,然后让Run()释放该内存

Run()中不需要这么多测试。由于您的c'tor参数已经与CreateThread()兼容,只需将函数和参数传递给CreateThread,您就可以了

问候


Torsten

如果对象将在析构函数中执行Join()(如果是活动线程),那么它会被认为是安全的吗?@KaiserJohaan确定,调用d'or的线程将阻塞,直到Run()函数完成。但是您通常不希望d'tor加入线程,因为您可能希望有多个线程对象指向同一个真正的执行线程。如果您的Thread类不可复制,则无法将Thread对象存储在容器中。@TorstenRobitzki“可能希望有多个Thread对象指向同一个真正的执行线程”-我保留永远不做这种事情的权利:)同样,在堆栈上构建Thread对象。同样地,使用任何不是指针类型的容器,因此需要任何类型的“实”复制构造函数来加载它myContainer“不好”,myContainer“好:)。我不明白为什么会有人试图在另一个线程堆栈上构建一个线程对象——这是一种将RAII带到多线程处理的尝试,因为我只看到了这样做的问题。@MartinJames线程对象不是执行线程,它不是一个有一组已注册线程的堆栈,也可能是一个CPU分配给它的堆栈。相反,Thread类型的对象只是执行线程的句柄、指针或引用。拥有线程容器的一个原因可能是拥有一个可配置大小的线程池。使用相同的函数启动n个线程,将所有句柄(又名类线程的对象)放入一个容器中,然后从容器中连接所有线程,如果你想停止线程池。Martin的意思是只保留线程指针/句柄,创建一个像容器一样的ThreadHelper/包装器-你给它句柄,它只是像dev一样在它上面执行函数,而对于多线程处理,按照线程指针而不是包装器维护线程列表,主线程也可以使用这些包装器。仅供参考,Boost.thread()是win32和pthreads的包装器。在最新版本的Boost(1.50)中,进行了更改,使API与C++11的
std::thead
相匹配。我很快在谷歌上搜索了几个C++11std::thread页面。两者都是从使用Thread->join()的示例开始的。这就像似曾相识一样:创建/终止/加入ad nauseum。Delphi、Java、C#和现在的C++11——都是老垃圾。标准委员会的成员是否真的编写过任何非平凡的多线程软件?为什么开发人员如此热衷于join()?什么教材/网页作者负责?应用程序线程和线程池的生命周期,很好,那么我们得到了什么:“join()”祝你好运-你需要它:)
    void Thread::Detach()
    {
        mState = Thread::DETACHED;
        mHandle = NULL;
        mArg = NULL;
        mFunctionPointer = NULL;
    }