Threads not running, why?

2019-09-01 01:52发布

I wrote a simple test application to prove that the threads work:

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

The output from this application is:

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

Continuously which is exactly what I would expect to see...Now in a much larger project I have a base 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;
    }

Finally a derived class that implements the thread class and provides the blnStart method:

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

An instance of the class clsOpenLDVrdr is created and the blnStart method called:

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

I can see in the debugger that "blnStart" is being called and stepping into it everything is executed...but the thread never runs.

Also tried using _beginthreadex instead of _beginthread:

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

No difference. There is some kind of incompatibility problem here as the simple example I created at the start of this post works and there isn't much difference between the two versions. Except maybe the way its used...the first simple example was created as a Windows console application. The project I'm having difficulty with is in a DLL.

I'm attaching to the DLL with the debugger and stepping through the code which works until it gets to the loop after the beginthread call then it just loops forever and never gets into the thread.

I just tried the following, adding a standalone thread with a standard C function:

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

I then modify the "_beginthread" call as follows:

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

Sadly the result is the same, the threadTest function is not called. But a valid handle is returned.

Found this:

unable to call a thread in dll file

Looks interesting and may explain the strange behaviour I'm experiencing.

1条回答
Juvenile、少年°
2楼-- · 2019-09-01 02:47

Solved...I didn't realise at first but for some reason the existing DLL had a call to:

    DisableThreadLibraryCalls(hInstance);

This prevents the threads from running. Having commented this out everything now works.

查看更多
登录 后发表回答