我编写了一个简单的测试应用程序来证明线程有效:
// 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
看起来很有趣,可以解释我遇到的奇怪行为。
答案 0 :(得分:1)
解决了......起初我没有意识到但是由于某种原因,现有的DLL有一个调用:
DisableThreadLibraryCalls(hInstance);
这可以防止线程运行。评论过这一切现在一切正常。