线程不是 运行,为什么?

Threads not running, why?

我写了一个简单的测试应用程序来证明线程工作:

    // 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        
    ...

不断,这正是我希望看到的......现在在一个更大的项目中,我有一个基础 class:

    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;
    }

最后一个派生的class实现线程class并提供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");
    }

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

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

我可以在调试器中看到 "blnStart" 正在被调用并进入其中,一切都已执行...但线程从未运行。

还尝试使用 _beginthreadex 而不是 _beginthread:

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

没有区别。这里存在某种不兼容问题,因为我在此 post 开始时创建的简单示例有效,并且两个版本之间没有太大区别。也许除了它的使用方式...第一个简单示例是作为 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

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

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

    DisableThreadLibraryCalls(hInstance);

这可以防止线程 运行。将其注释掉后一切正常。