我正在使用Windows功能开发串行通信软件。 在这个CSerialCommhelper中是一个处理所有串行通信函数的类,CphysicalLayer是一个使用该类的函数。
class CSerialCommHelper :
public CCommAgent
{
HANDLE m_pPortHandle; //Handle to the COM port
HANDLE m_hReadThread; //Handle to the Read thread
HANDLE m_hPortMutex; //Handle to Port Mutex
std::wstring m_strPortName; //Portname
COMMTIMEOUTS m_CommTimeouts; //Communication Timeout Structure
_DCB dcb; //Device Control Block
DWORD m_dwThreadID; //Thread ID
public:
CSerialCommHelper(CPhysicalLayer *);
virtual HRESULT Open();
virtual HRESULT ConfigPort();
static void * ReadThread(void *);
virtual HRESULT Write(const unsigned char *,DWORD);
virtual HRESULT Close();
//virtual HRESULT Flush(DWORD dwFlag = PURGE_TXCLEAR | PURGE_RXCLEAR);
wstring StringToWstring(const string &);
~CSerialCommHelper(void);
};
CommAgent包含一个CphysicalLayer指针,用于在收到数据时通知physicalLayer。
HRESULT CSerialCommHelper::Write(const unsigned char *pucDataToWrite,DWORD ulLength)
{
unsigned long bytesWritten=0, ij = 0;
WaitForSingleObject(m_hPortMutex,INFINITE);
if(WriteFile(m_pPortHandle,pucDataToWrite,ulLength,&bytesWritten,NULL))
{
if(!ReleaseMutex(m_hPortMutex))
{
DWORD err=GetLastError();
// Mutex released succesfully..
}
}
if (bytesWritten != ulLength)
return E_FAIL;
return S_OK;
}
void * CSerialCommHelper::ReadThread(void * pObj)
{
CSerialCommHelper *pCSerialCommHelper =(CSerialCommHelper *)pObj;
DWORD dwBytesTransferred = 0;
unsigned char byte = 0;
while (pCSerialCommHelper->m_pPortHandle != INVALID_HANDLE_VALUE)
{
pCSerialCommHelper->m_strBuffer.clear();
pCSerialCommHelper->m_usBufSize=0;
WaitForSingleObject(pCSerialCommHelper->m_hPortMutex,INFINITE);
do
{
dwBytesTransferred = 0;
ReadFile (pCSerialCommHelper->m_pPortHandle, &byte, 1, &dwBytesTransferred, 0);
if (dwBytesTransferred == 1)
{
pCSerialCommHelper->m_strBuffer.push_back(byte);
pCSerialCommHelper->m_usBufSize++;
continue;
}
}
while (dwBytesTransferred == 1);
if(pCSerialCommHelper->m_usBufSize!=0)
{
CProtocolPacket *pCProtocolPacket = new CProtocolPacket(0,2048);
pCProtocolPacket->AddBody(pCSerialCommHelper->m_usBufSize,(unsigned char*)pCSerialCommHelper->m_strBuffer.c_str());
pCSerialCommHelper->m_pCPhysicalLayer->Data_ind(pCProtocolPacket);
delete pCProtocolPacket;
}
ReleaseMutex(pCSerialCommHelper->m_hPortMutex);
Sleep(2);
}
ExitThread(0);
return 0;
}
这就是我创建文件和互斥的方式
m_pPortHandle = CreateFile(m_strPortName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING,NULL, NULL );
if (m_pPortHandle == INVALID_HANDLE_VALUE)
{
return E_HANDLE;
//throw failure
}
m_hPortMutex = CreateMutex(NULL,TRUE,L"MY_MUTEX");
if( m_hReadThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadThread,(LPVOID)this,0,&m_dwThreadID))
{
}
else
{
return E_FAIL;
}
return S_OK;
但是在将字符串写入端口后,write函数正在成功释放互斥锁,但读取线程仍在等待。
答案 0 :(得分:2)
创建互斥锁时,将 bInitialOwner 参数设置为TRUE。所以在这一点上,互斥锁由主线程拥有。
m_hPortMutex = CreateMutex(NULL,TRUE,L"MY_MUTEX");
然后创建ReadThread
,尝试获取互斥锁。这显然会在主线程释放它之前阻塞。
WaitForSingleObject(pCSerialCommHelper->m_hPortMutex,INFINITE);
当主线程尝试写东西时,它首先要做的是尝试再次获取互斥锁。
WaitForSingleObject(m_hPortMutex,INFINITE);
由于主线程已拥有互斥锁,此调用将立即返回而不会阻塞,但在此阶段,您现在已经在主线程中获取了两次互斥锁(一次在CreateMutex
调用中,第二次与WaitForSingleObject
)。
当您完成对文件的写入后,您将通过此调用释放互斥锁:
if(!ReleaseMutex(m_hPortMutex))
但是只发布一次,所以它仍然由主线程拥有,而读线程将继续阻塞。
最重要的是,在创建互斥锁时,应将 bInitialOwner 参数设置为FALSE。
m_hPortMutex = CreateMutex(NULL,FALSE,L"MY_MUTEX");
拥有互斥锁的线程可以在重复的等待函数调用中指定相同的互斥锁,而不会阻止其执行。 [...]但是,要释放其所有权,每次互斥锁满足等待时,线程必须调用一次ReleaseMutex。
答案 1 :(得分:1)
在您的代码中,我看到以下问题:
Write()
在错误时不会释放互斥锁。我猜你从构造函数调用的同一个线程中调用Write()
,这是因为它已经拥有了互斥锁。在此之后,互斥锁仍归线程所有。使另一个线程阻塞。
我建议您在检查之外移动释放调用是否写入成功(因为您总是需要释放它)。
您应该注意,每次获得互斥锁时都需要调用ReleaseMutex()
CreateMutex()
,bInitialOwner
设置为TRUE
,或成功{ {1}}调用互斥锁。
答案 2 :(得分:1)
问题在于ReadThread中的Readfile函数。它没有正确返回。 我不知道原因。
void * CSerialCommHelper::ReadThread(void * pObj)
{
CSerialCommHelper *pCSerialCommHelper =(CSerialCommHelper *)pObj;
DWORD dwBytesTransferred =0;
char byte[1];
string buffer;
while (pCSerialCommHelper->m_pPortHandle != INVALID_HANDLE_VALUE)
{
WaitForSingleObject(pCSerialCommHelper->m_hPortMutex,INFINITE);
do
{
dwBytesTransferred = 0;
bool bReadResult= false;
bReadResult = ReadFile (pCSerialCommHelper->m_pPortHandle,byte,1,&dwBytesTransferred,NULL);
if (dwBytesTransferred == 1)
{
buffer.push_back(byte[0]);
continue;
}
}
while (dwBytesTransferred == 1);
pCSerialCommHelper->m_pCPhysicalLayer->Data_ind((unsigned char *)buffer.c_str());
ReleaseMutex(pCSerialCommHelper->m_hPortMutex);
}
ExitThread(0);
return 0;
}
我尝试使用此代码段替换代码,发现bReadResult未正确更新。
答案 3 :(得分:0)
尝试创建没有名称的互斥锁。命名互斥锁通常用于进程间通信。通常,用于进程内线程之间的通信的互斥锁不会被命名 - 它们不需要按名称打开,因为所有进程线程都可以访问互斥锁句柄。