windows - 在 SerialCommunication C++ 中使用 Mutex 时出现多线程问题

标签 windows multithreading visual-c++ serial-port mutex

我正在开发一个使用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;

但是在将字符串写入端口后,写入函数成功释放互斥量,但读取线程仍在等待。

最佳答案

创建互斥量时,将 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");

引用CreateMutex documentation :

The thread that owns a mutex can specify the same mutex in repeated wait function calls without blocking its execution. [...] However, to release its ownership, the thread must call ReleaseMutex once for each time that the mutex satisfied a wait.

关于windows - 在 SerialCommunication C++ 中使用 Mutex 时出现多线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17274491/

相关文章:

c++ - 以编程方式为 Windows 简化调度任务

c++ - 使c++程序以交互方式将输入输出传递给windows命令提示符

c++ - Windows7 API,在哪里可以找到它

python - Astroscrappy 无法在多处理 Jupyter 上工作

c++ - 如何删除由 GLUT 创建的窗口的边框?

c++ - 使用 "cin"进行用户输入验证

visual-c++ - Visual C++ 2005不会为链接器添加/dll参数

windows - 如何使用 Linux 实例化/运行 Ruby 程序(使用 Watir)?

c - 在 Raspberry Pi 2 上使用多线程进行 SDL2 渲染

multithreading - NSOpenGLLayer 和多线程