导入一个已经可以正常工作的日志类。
如果做不到这一点,请开始使用 Windows 等待函数在互斥体上等待来修复您的代码。如果你用谷歌搜索'WaitForSingleObject',你应该能够很容易地使用它——你需要将互斥体句柄传递给每个线程,以便他们可以等待它。您显然可以编写足够好的代码,您只需要更多线程、信号和线程间通信方面的经验。
哦 - 看看 'lpLogString' 的生命周期 - 它在哪里处理?我没有使用过 TCHAR,但是,AFAIK,所有新的东西都应该被处理掉。我猜它应该在写入文件后在写入线程中处理。
你真的需要重构你的整个设计,只使用一个在队列中等待东西的线程。为每次写入创建新线程效率极低,并且可能导致写入顺序有点不确定,因为线程获取互斥锁的顺序不能保证是 FIFO。
您将“lpLogString”作为 CreateThread() 参数传递给每个线程(正确!),但不会在写入线程中检索它!你必须在每个写入线程中使用'LPVOID lpParam'来检索字符串数据,否则会有很大的问题。
..这最终导致了这样的想法'所有这些数据仅通过一个指针传递给线程,我不妨声明一个可以包含格式字符串、互斥句柄和其他任何东西的类。然后我可以创建一个,加载它并将其指针传递给线程。它可以包含所有这些特殊的格式化命令和代码作为方法——然后写入线程可以进行所有格式化,这样我的主应用程序就不必这样做了。线程可以在稍后处理完 'thread comms' 实例后对其进行 dispose()。
..这最终导致了一个想法'现在我有了这个'线程通信'类,我可以将它的实例排队到生产者-消费者队列上的一个线程,而不是不断地创建新线程。我可以将生产者-消费者队列的实例传递给 LPVOID lpParam 事物中的线程。
//在标题中:
class ThreadComms {
private:
public:
int dataLen;
TCHAR *lpLogString;
HANDLE hMutex;
ThreadComms(String data);
~ThreadComms();
};
//在cpp中
ThreadComms::ThreadComms(String data){
dataLen=data.Length();
lpLogString=new TCHAR[dataLen+1];
strcpy(( char *)lpLogString,(char *)data.c_str());
};
ThreadComms::~ThreadComms(){
delete(lpLogString);
};
HANDLE hthread;
DWORD dwthreadid;
DWORD _stdcall MyThreadFunction(LPVOID lpParam)
{
ThreadComms *inThreadComms=(ThreadComms *)lpParam;
DWORD dwNumBytesWritten = 0;
HANDLE hFile;
WaitForSingleObject(inThreadComms->hMutex,INFINITE);
hFile = CreateFile(FILENAME,
FILE_APPEND_DATA,
FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
WriteFile(hFile,
(char *)inThreadComms->lpLogString,
inThreadComms->dataLen,
(LPDWORD)&dwNumBytesWritten,
NULL );
CloseHandle( hFile );
ReleaseMutex(inThreadComms->hMutex);
delete(inThreadComms);
}
void myfn(const String inMess)
{
HANDLE hMutex;
hMutex=CreateMutex(NULL,FALSE,"");
assert(hMutex!=NULL);
ThreadComms *threadComms=new(ThreadComms)(inMess);
CreateThread(NULL,
0,
MyThreadFunction,
threadComms,
0,
&dwthreadid);
CloseHandle(hthread);
}
..或者,更好的例子,(至少,它在 C++ Builder 中):
//在标题中:
class PCqueue{
private:
CRITICAL_SECTION access;
deque<void*> *objectQueue;
HANDLE queueSema;
public:
PCqueue();
void push(void *ref);
bool pop(void**ref,DWORD timeout);
};
class ThreadComms {
private:
public:
int dataLen;
TCHAR *lpLogString;
ThreadComms(String data);
~ThreadComms();
};
class ThreadLogger {
private:
PCqueue *queue;
HANDLE logThread;
HANDLE fileAccess;
AnsiString Ffilename;
static DWORD _stdcall staticThreadRun(void *param){
((ThreadLogger*)param)->threadRun(0);
};
public:
void threadRun(void *param);
ThreadLogger(String filename);
void logString(String data);
};
//在cpp中:
PCqueue::PCqueue(){
objectQueue=new deque<void*>;
InitializeCriticalSection(&access);
queueSema=CreateSemaphore(NULL,0,MAXINT,NULL);
};
void PCqueue::push(void *ref){
EnterCriticalSection(&access);
objectQueue->push_front(ref);
LeaveCriticalSection(&access);
ReleaseSemaphore(queueSema,1,NULL);
};
bool PCqueue::pop(void **ref,DWORD timeout){
if (WAIT_OBJECT_0==WaitForSingleObject(queueSema,timeout)) {
EnterCriticalSection(&access);
*ref=objectQueue->back();
objectQueue->pop_back();
LeaveCriticalSection(&access);
return(true);
}
else
return(false);
};
ThreadComms::ThreadComms(String data){
dataLen=data.Length();
lpLogString=new TCHAR[dataLen+1];
int index=0;
for(index=0;index<dataLen;index++){lpLogString[index]=data[index+1];};
};
ThreadComms::~ThreadComms(){
delete(lpLogString);
};
ThreadLogger::ThreadLogger(String filename){
Ffilename=filename;
fileAccess=CreateMutex(NULL,FALSE,"Example Mutex");
queue=new PCqueue();
logThread=CreateThread(NULL,
0,
staticThreadRun,
this,
0,
0);
};
void ThreadLogger::threadRun(void *param){
ThreadComms *inMess;
DWORD dummy;
while(queue->pop((void**)&inMess, INFINITE)){
HANDLE hFile;
WaitForSingleObject(fileAccess,INFINITE);
hFile = CreateFile( &Ffilename[1],
FILE_APPEND_DATA,
FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
WriteFile(hFile,
(char *)inMess->lpLogString,
inMess->dataLen,
&dummy,
NULL );
CloseHandle( hFile );
ReleaseMutex(fileAccess);
delete(inMess);
};
};
void ThreadLogger::logString(String data){
ThreadComms *threadComms=new(ThreadComms)(data);
queue->push(threadComms);
};