线程没有运行,为什么?

时间:2018-04-04 14:03:19

标签: c++ beginthread

我编写了一个简单的测试应用程序来证明线程有效:

    // Test.cpp : Defines the entry point for the console application.
    //

    #include "stdafx.h"

    class clsTest {
    private:
        uintptr_t muintHandle;

        static unsigned int __stdcall fnThread(void* pData) {
            while( 1 ) {
                _sleep(1000);
                printf("In fnThread, handle = %d\n", *(uintptr_t*)pData);
            }
            return 0;
        }
    public:
        clsTest() {
            muintHandle = _beginthreadex(0, 0, &clsTest::fnThread, (void*)&muintHandle, 0, 0);
            printf("clsTest(), after beginthreadex, handle = %u\n", muintHandle);
        }
    };

    int _tmain(int argc, _TCHAR* argv[]) {
        clsTest* pT = NULL;

        while(1) {
            printf("From _tmain\n");

            if ( pT == NULL ) {
                pT = new clsTest();
            }
            _sleep(1000);
        }
        return 0;
    }

此应用程序的输出是:

    From _tmain
    clsTest(), after beginthreadex, handle = 112
    In fnThread, handle = 112
    From _tmain
    In fnThread, handle = 112
    From _tmain
    In fnThread, handle = 112
    From _tmain
    In fnThread, handle = 112
    From _tmain
    In fnThread, handle = 112
    From _tmain
    In fnThread, handle = 112        
    ...

这正是我期望看到的......现在在一个更大的项目中,我有一个基类:

    typedef enum {
            eIdle = 0,      //Thread is not working at all
            eStarted,       //Thread has been started but is not fully operational yet
            eRunning,       //Thread is working normally
            ePausing,       //Thread is requested to enter the paused state
            ePaused,        //Thread is paused
            eTerminating    //Termination has been requested but not completed yet
        } eThreadStates; 

    class clsOpenLDVthread {
    protected:
        volatile eThreadStates meState;
        CRITICAL_SECTION mCritControl;  // critical section for thread control
        char mszName[80];
        HANDLE mhEvent, mhThread;
        virtual bool blnStart() = 0;

    public:
        clsOpenLDVthread(LPCSTR pszName);
        ~clsOpenLDVthread();

        bool inline blnIsRunning();
        bool inline blnIsStopped();
        bool inline blnIsStopping();
        bool inline blnIsStarting();
        bool inline blnIsPausing();
        bool inline blnIsPaused();
        bool blnPause(bool blnState);
        virtual bool blnStop();
    };

    clsOpenLDVthread::clsOpenLDVthread(LPCSTR pszName) : meState(eIdle)
                                               , mhThread(NULL) {
        ::InitializeCriticalSection(&mCritControl); //Get a critical section
        //Get a unique name for signaling event
        sprintf(mszName, "%s%d", pszName, ::GetCurrentProcessId());
        //Get the event object
        mhEvent = ::CreateEvent(NULL, FALSE, FALSE, mszName);
    }       
    clsOpenLDVthread::~clsOpenLDVthread() {
        if ( blnIsPaused() ) {
            blnPause(false);
        }
        if ( blnIsRunning() ) {
            blnStop();
        }
        if ( mhEvent ) {
            ::CloseHandle(mhEvent);
            mhEvent = NULL;
        }
        ::DeleteCriticalSection(&mCritControl);
    }
    bool clsOpenLDVthread::blnIsPaused() {
        return meState == ePaused;
    }
    bool clsOpenLDVthread::blnIsPausing() {
        return meState == ePausing;
    }
    bool clsOpenLDVthread::blnIsRunning() {
        return meState == eRunning;
    }
    bool clsOpenLDVthread::blnIsStarting() {
        return meState == eStarted;
    }
    bool clsOpenLDVthread::blnIsStopped() {
        return meState == eIdle;
    }
    bool clsOpenLDVthread::blnIsStopping() {
        return meState == eTerminating;
    }
    bool clsOpenLDVthread::blnPause(bool blnState) {
        bool blnResult = mhThread != NULL;
        if ( blnResult ) {
            if ( blnState ) {
                unsigned uintCountDown = 10u;

                if ( blnIsRunning() || blnIsPausing() ) {
                    meState = ePausing;
                    while( blnIsPausing() && -- uintCountDown ) {
                        ::SetEvent(mhEvent);
        //Give thread chance to run and pause
                        _sleep(751);
                    }
                    blnResult = blnIsPaused();
                }
            } else {
                if ( blnIsPaused() ) {
                    meState = eRunning;
                    //this will need replacing...mhThread->ResumeThread();
                }
                blnResult = true;
            }
        }
        return blnResult;
    }
    bool clsOpenLDVthread::blnStop() {
        bool blnResult = meState == eIdle;
        unsigned uintCountDown = 100u;

        if ( blnIsPaused() ) {
            blnPause(false);
        }
        if ( blnIsRunning() ) {
            meState = eTerminating;

            while( !blnIsStopped() && --uintCountDown ) {
                if ( mhEvent ) {
                    ::SetEvent(mhEvent);
                }
        //Give thread a change to run and terminate
                _sleep(501);
            }
            blnResult = blnIsStopped();
            mhThread = NULL;
        }
        return blnResult;
    }

最后是一个实现线程类并提供blnStart方法的派生类:

    class clsOpenLDVrdr : public clsOpenLDVthread {
    public:
    //Maximum size of uplink data per single transfer
        static const unsigned mscuBuffersize;
    private:
    //The thread's main routine
        static void msgReaderThread(LPVOID lpParam);

    public:
        clsOpenLDVrdr();
        virtual ~clsOpenLDVrdr();
    //Call this to start the thread, see clsOpenLDVthread for more operations
        virtual bool blnStart();
    };

    const unsigned clsOpenLDVrdr::mscuBuffersize = MAX_OPENLDV_DATA;

    clsOpenLDVrdr::clsOpenLDVrdr() : clsOpenLDVthread(_T("EvOpenLDVrdr")) {
    }
    clsOpenLDVrdr::~clsOpenLDVrdr() {
    }
    bool clsOpenLDVrdr::blnStart() {
        bool blnResult = false;
        if ( blnIsStopped() ) {
            meState = eStarted;
        //Create the thread
            mhThread = (HANDLE)_beginthread(&clsOpenLDVrdr::msgReaderThread
                                            ,0, NULL);
            blnResult = mhThread != NULL;

            while( blnResult && (meState == eStarted) ) {
        //Give the thread chance to start and initialize
                _sleep(501);
            }
        }
        return blnResult && (meState == eRunning);
    }
    void clsOpenLDVrdr::msgReaderThread(LPVOID lpParam) {
            OutputDebugString("msgReaderThread\n");
    }

创建了类clsOpenLDVrdr的实例,并调用了blnStart方法:

    clsOpenLDVrdr* pobjReader = new clsOpenLDVrdr();
    pobjReader->blnStart();

我可以在调试器中看到正在调用“blnStart”并踩到它所有内容都被执行...但是线程永远不会运行。

还尝试使用_beginthreadex而不是_beginthread:

    mhThread = (HANDLE)_beginthreadex(0, 0, pfnThread, pobParam, 0, 0);

没有区别。这里有一些不兼容问题,因为我在本文开头创建的简单示例有效,两个版本之间没有太大区别。除了它的使用方式之外......第一个简单的例子是作为Windows控制台应用程序创建的。我遇到困难的项目是在DLL中。

我正在使用调试器附加到DLL并逐步执行代码,直到它在beginthread调用之后进入循环,然后它才会永远循环并且永远不会进入线程。

我刚刚尝试了以下内容,添加了一个带有标准C函数的独立线程:

    unsigned __stdcall threadTest(void* pobjData) {
        OutputDebugString("threadTest\n");
        return 0;
   }

然后我按如下方式修改“_beginthread”调用:

    mhThread = (HANDLE)_beginthreadex(0, 0, threadTest, pobjParam, 0, 0);

可悲的是结果是一样的,没有调用threadTest函数。但是返回一个有效的句柄。

发现这个:

unable to call a thread in dll file

看起来很有趣,可以解释我遇到的奇怪行为。

1 个答案:

答案 0 :(得分:1)

解决了......起初我没有意识到但是由于某种原因,现有的DLL有一个调用:

    DisableThreadLibraryCalls(hInstance);

这可以防止线程运行。评论过这一切现在一切正常。