多线程下使用CloseHandle关闭串口导致阻塞怎么解决

Hippop314 2018-11-09 10:30:20
我在用MFC做一个上位机软件,因为用到串口通信,所以开了一个线程去阻塞读取串口,读取完成之后,通知主线程处理。代码如下:

线程工作函数:

//执行Dlg工作线程
static DWORD WINAPI RunCmcucontrollerDlg_Thread(LPVOID arg)
{
CmcucontrollerDlg *dlg = (CmcucontrollerDlg *)arg;

return dlg->uartWorkThread();
}

创建线程的代码:

//创建信号量
this->readSem = CreateSemaphore(0, 0, 1, 0);
if (this->readSem == NULL)
{
CString str;
DWORD errCode;

errCode = GetLastError();
str.Format(L"创建信号量失败,错误(%d):%s", errCode, GetLastErrorToString(errCode));
::MessageBox(0, str, L"初始化失败", MB_OK);

AfxGetMainWnd()->SendMessage(WM_CLOSE);
return FALSE;
}

//创建工作线程
uartWorkHandle = CreateThread(NULL, 0, RunCmcucontrollerDlg_Thread, (LPVOID)this, 0, &uartWorkThreadId);
if (uartWorkHandle == NULL)
{
CString str;
DWORD errCode;

errCode = GetLastError();
str.Format(L"创建工作线程失败,错误(%d):%s", errCode, GetLastErrorToString(errCode));
::MessageBox(0, str, L"初始化失败", MB_OK);

AfxGetMainWnd()->SendMessage(WM_CLOSE);
}

打开串口部分:

//打开串口
this->uartHandle = CreateFileW(str,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (!this->uartHandle || this->uartHandle == INVALID_HANDLE_VALUE)
{
this->uartHandle = 0;
errCode = GetLastError();
str.Format(L"串口打开失败,错误(%d):%s", errCode, GetLastErrorToString(errCode));
::MessageBox(0, str, L"打开失败", MB_OK);
return;
}

//设置串口参数
errCode = SetUartParam(this->uartHandle,
baudrate,
dataBits,
parityCheck,
stopBits);
if (errCode)
{
CloseHandle(this->uartHandle);
this->uartHandle = 0;

str.Format(L"串口参数设置失败,错误(%d):%s", errCode, GetLastErrorToString(errCode));
::MessageBox(0, str, L"串口设置失败", MB_OK);
return;
}

//通知线程接收数据
::ReleaseSemaphore(this->readSem, 1, NULL);

工作线程部分:

DWORD CmcucontrollerDlg::uartWorkThread()
{
HWND hwnd = this->GetSafeHwnd();

while (1)
{
WaitForSingleObject(this->readSem, INFINITE);
if (this->uartWorkerTheadExit)
{
break;
}

//读取串口
if (ReadFile(this->uartHandle, this->recvBuffer, sizeof(this->recvBuffer), &this->recvCount, NULL))
{
this->recvError = 0;
}
else
{
this->recvError = GetLastError();
}

//通知主线程
::PostMessage(hwnd, WM_ON_UART_READ, 0, 0);
}

return 0;
}

点击关闭按钮的代码

//关闭串口
if (this->uartHandle)
{
CloseHandle(this->uartHandle);
this->uartHandle = NULL;

openButton->SetWindowTextW(L"打开");
portsBox->EnableWindow(true);
baudrateBox->EnableWindow(true);
dataBitsBox->EnableWindow(true);
parityCheckBox->EnableWindow(true);
stopBitsBox->EnableWindow(true);
dataTimeoutBox->EnableWindow(true);
}

现在的问题是,我打开串口成功之后,工作线程就阻塞地读取串口。然后我点击关闭按钮,程序卡死。
单步运行时发现,主线程阻塞在CloseHandle上,工作线程阻塞在ReadFile上。

大家有遇到这个问题吗?怎么解决?在线等。。
...全文
475 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
mirro 2018-11-16
  • 打赏
  • 举报
回复
异步程序需要初始化呢……
schlafenhamster 2018-11-09
  • 打赏
  • 举报
回复
单个串口
线程 只 负责 读 写 , 初始化 等 在 主程序 中 !
Hippop314 2018-11-09
  • 打赏
  • 举报
回复
引用 5 楼 zgl7903 的回复:
[quote=引用 4 楼 xiaoliang10086 的回复:] [quote=引用 2 楼 zgl7903 的回复:] 三种方式 1 异步模式 (OVERLAP) 2 设置超时, 使读立即返回 ComTimeouts.ReadIntervalTimeout = MAXDWORD; ComTimeouts.ReadTotalTimeoutMultiplier = 0; ComTimeouts.ReadTotalTimeoutConstant = 0; 3 读之前 ClearCommError, 检查 COMSTAT 中的 缓冲区数据量cbInQue, 按这个量取数据
多线程读写串口难道不能这么用吗?[/quote] 我的意思是三种方式的任何一个都可以解决你的问题, 用2,3你的代码改动量很小 [/quote]谢谢,不过我自己解决了,使用CancelSynchronousIo使被阻塞的工作线程返回Error,再使用CloseHandle就没问题了

	//关闭串口
	if (this->uartHandle)
	{
		//取消读操作
		CancelSynchronousIo(this->uartWorkHandle);

		//关闭串口
		CloseHandle(this->uartHandle);
		this->uartHandle = NULL;

		openButton->SetWindowTextW(L"打开");
		portsBox->EnableWindow(true);
		baudrateBox->EnableWindow(true);
		dataBitsBox->EnableWindow(true);
		parityCheckBox->EnableWindow(true);
		stopBitsBox->EnableWindow(true);
		dataTimeoutBox->EnableWindow(true);
	}
zgl7903 2018-11-09
  • 打赏
  • 举报
回复
官方指导文档 Serial Communications in Win32



zgl7903 2018-11-09
  • 打赏
  • 举报
回复
引用 4 楼 xiaoliang10086 的回复:
[quote=引用 2 楼 zgl7903 的回复:]
三种方式
1 异步模式 (OVERLAP)
2 设置超时, 使读立即返回
ComTimeouts.ReadIntervalTimeout = MAXDWORD;
ComTimeouts.ReadTotalTimeoutMultiplier = 0;
ComTimeouts.ReadTotalTimeoutConstant = 0;
3 读之前 ClearCommError, 检查 COMSTAT 中的 缓冲区数据量cbInQue, 按这个量取数据
多线程读写串口难道不能这么用吗?[/quote]
我的意思是三种方式的任何一个都可以解决你的问题, 用2,3你的代码改动量很小

Hippop314 2018-11-09
  • 打赏
  • 举报
回复
引用 2 楼 zgl7903 的回复:
三种方式 1 异步模式 (OVERLAP) 2 设置超时, 使读立即返回 ComTimeouts.ReadIntervalTimeout = MAXDWORD; ComTimeouts.ReadTotalTimeoutMultiplier = 0; ComTimeouts.ReadTotalTimeoutConstant = 0; 3 读之前 ClearCommError, 检查 COMSTAT 中的 缓冲区数据量cbInQue, 按这个量取数据
多线程读写串口难道不能这么用吗?
Hippop314 2018-11-09
  • 打赏
  • 举报
回复
引用 1 楼 schlafenhamster 的回复:
多个串口 ?
单个串口
zgl7903 2018-11-09
  • 打赏
  • 举报
回复
三种方式
1 异步模式 (OVERLAP)
2 设置超时, 使读立即返回
ComTimeouts.ReadIntervalTimeout = MAXDWORD;
ComTimeouts.ReadTotalTimeoutMultiplier = 0;
ComTimeouts.ReadTotalTimeoutConstant = 0;
3 读之前 ClearCommError, 检查 COMSTAT 中的 缓冲区数据量cbInQue, 按这个量取数据
schlafenhamster 2018-11-09
  • 打赏
  • 举报
回复
多个串口 ?

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧