Темы не работают, почему?

Я написал простое тестовое приложение, чтобы доказать, что потоки работают:

    // 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 не вызывается. Но верный дескриптор возвращается.

Нашел это:

невозможно вызвать поток в файл DLL

Выглядит интересно и может объяснить странное поведение, которое я испытываю.

0

Решение

Решено … Сначала я не осознавал, но по какой-то причине существующая DLL вызывала:

    DisableThreadLibraryCalls(hInstance);

Это предотвращает запуск потоков. Закомментировав все это, теперь все работает.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]