在DLL中用AfxBeginThread后,为何调用程序就会卡住不动了?

lidamingnew123 2019-04-19 08:48:25
各位大佬:您们好!

我想在DLL中用CSerialPortEx类,来进行串口通讯,最最关键的一个地方BOOL CSerialPortEx::StartMonitoring()
{
if (!(m_Thread = AfxBeginThread((AFX_THREADPROC)CommThread, this))) //////////就是这个地方
return FALSE;
TRACE("Thread started\n");
return TRUE;
}

当用AfxBeginThread启动线程CommThread后,调用该DLL的程序就卡死了,假如将启动线程那个语句屏蔽了后,就不会卡死,当然线程页没有启动,但是我用同样的代码用在不是DLL的普通MFC程序里初始化串口并开启CommThread线程,没有一点问题,是同样的串口类 CSerialPortEx的代码,请问各位朋友及专家们,在DLL中要使用串口类,开线程是否有什么特殊的要注意的地方?请指点,谢谢!

我将具体的CSerialPortEx类代码附上:
////////////////H文件//////////////////////////
//CSerialPortEx类是在Remon Spekreijse设计的CSerialPort类基础上设计的,并增加
//了对二进制数据传输和块读写方式的支持和其他功能函数。关于CSerialPort类的声明如下:

/*
** PURPOSE This class can read, write and watch one serial port.
** It sends messages to its owner when something happends on the port
** The class creates a thread for reading and writing so the main
** program is not blocked.
**
*/

#ifndef __GZSERIALPORT_H__
#define __GZSERIALPORT_H__

class CSerialPortEx
{
public:
CSerialPortEx();
virtual ~CSerialPortEx();

BOOL InitPort(/*HWND hOwner,*/CString sPort, UINT baud, char parity, UINT databits, UINT stopsbits, DWORD dwCommEvents, UINT nBufferSize);

BOOL StartMonitoring();
BOOL RestartMonitoring();
BOOL StopMonitoring();

DWORD GetWriteBufferSize();
DWORD GetCommEvents();

DCB GetDCB();


//接口函数
void Close();
BOOL Open(int nPort, UINT uBaud);
BOOL WriteComBlock(unsigned char *pBlock, int nLength);
void ReceiveByte(unsigned char uc);
CString m_strReceived;//接收字符串
int m_nProcessLength;//程序处理串口接收数据的最小长度
void ReadProcess();
int ReadCommBlock(unsigned char *pBlock, int nMaxLength);


public:
void WriteToPort(BYTE* string,int nLength);
void WriteToPort(CString str);

protected:
// protected memberfunctions
void ProcessErrorMessage(char* ErrorText);
static UINT CommThread(LPVOID pParam);
static void ReceiveChar(CSerialPortEx* port, COMSTAT comstat);
static void WriteChar(CSerialPortEx* port);
public:
static BYTE* ReadBlock(CSerialPortEx *port, int& readLen);
HANDLE m_hComm;

protected:

int m_nToSend;

// thread
CWinThread* m_Thread;

// synchronisation objects
CRITICAL_SECTION m_csCommunicationSync;


// handles
HANDLE m_hShutdownEvent;

HANDLE m_hWriteEvent;

// Event array.
// One element is used for each event. There are two event handles for each port.
// A Write event and a receive character event which is located in the overlapped structure (m_ov.hEvent).
// There is a general shutdown when the port is closed.
HANDLE m_hEventArray[3];

// structures
OVERLAPPED m_ov;
COMMTIMEOUTS m_CommTimeouts;

CString m_strRec;


public:
UINT m_nPortNr;
BYTE* m_szWriteBuffer;
DWORD m_dwCommEvents;
DWORD m_nWriteBufferSize;
DCB m_dcb;

BOOL m_bThreadAlive;
BOOL m_bBlockRead;

public:

};

#endif __GZSERIALPORT_H__


///////////////cpp文件////////////////////////


//CSerialPortEx类是在Remon Spekreijse设计的CSerialPort类基础上设计的,并增加
//了对二进制数据传输和块读写方式的支持和其他功能函数。关于CSerialPort类的声明如下:

/*
** PURPOSE This class can read, write and watch one serial port.
** It sends messages to its owner when something happends on the port
** The class creates a thread for reading and writing so the main
** program is not blocked.
*/

#include "stdafx.h"
#include "SerialPort.h"

#include <assert.h>

const WORD nPackSize=0x1000;
//const int nSendBuffer=nPackSize*10;


CSerialPortEx::CSerialPortEx()
{
m_hComm = NULL;

// initialize overlapped structure members to zero
m_ov.Offset = 0;
m_ov.OffsetHigh = 0;

// create events
m_ov.hEvent = NULL;
m_hWriteEvent = NULL;
m_hShutdownEvent = NULL;

m_szWriteBuffer = NULL;

m_bThreadAlive = FALSE;//线程初始化运行状态为否
m_bBlockRead=FALSE;

m_Thread=NULL;//辅助线程指针

m_nProcessLength=10;//最短命令长度
}


CSerialPortEx::~CSerialPortEx()
{
do
{
SetEvent(m_hShutdownEvent);
} while (m_bThreadAlive);

TRACE("Thread ended\n");

delete [] m_szWriteBuffer;
}

//
// Initialize the port.
//
BOOL CSerialPortEx::InitPort(//HWND hOwner,// the owner (CWnd) of the port (receives message)
CString sport, // portnumber (1..4)
UINT baud, // baudrate
char parity, // parity
UINT databits, // databits
UINT stopbits, // stopbits
DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc
UINT writebuffersize) // size to the writebuffer
{
// if the thread is alive: Kill
if (m_bThreadAlive)
{
do//直至辅助线程终止,否则等待
{
SetEvent(m_hShutdownEvent);
} while (m_bThreadAlive);
TRACE("Thread ended\n");
}

// create events
if (m_ov.hEvent != NULL)
ResetEvent(m_ov.hEvent);
m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (m_hWriteEvent != NULL)
ResetEvent(m_hWriteEvent);
m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (m_hShutdownEvent != NULL)
ResetEvent(m_hShutdownEvent);
m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

// initialize the event objects
m_hEventArray[0] = m_hShutdownEvent; // highest priority
m_hEventArray[1] = m_ov.hEvent;
m_hEventArray[2] = m_hWriteEvent;

// initialize critical section
InitializeCriticalSection(&m_csCommunicationSync);

// set buffersize for writing and save the owner
if (m_szWriteBuffer != NULL)
delete [] m_szWriteBuffer;
m_szWriteBuffer =new BYTE[writebuffersize];

m_nWriteBufferSize = writebuffersize;
m_dwCommEvents = dwCommEvents;

BOOL bResult = FALSE;
char *szBaud = new char[50];

// now it critical!
EnterCriticalSection(&m_csCommunicationSync);

// if the port is already opened: close it
if (m_hComm != NULL)
{
CloseHandle(m_hComm);
m_hComm = NULL;
}

// prepare port strings
sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);

// get a handle to the port
m_hComm = CreateFile(sport, // communication port string (COMX)
GENERIC_READ | GENERIC_WRITE, // read/write types
0, // comm devices must be opened with exclusive access
NULL, // no security attributes
OPEN_EXISTING, // comm devices must use OPEN_EXISTING
FILE_FLAG_OVERLAPPED, // Async I/O
0); // template must be 0 for comm devices

if (m_hComm == INVALID_HANDLE_VALUE)
{
// port not found
delete [] szBaud;

return FALSE;
}

// set the timeout values
m_CommTimeouts.ReadIntervalTimeout = 1000;
m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;
m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;
m_CommTimeouts.WriteTotalTimeoutConstant = 1000;

// configure
if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
{
if (SetCommMask(m_hComm, dwCommEvents))
{
if (GetCommState(m_hComm, &m_dcb))
{
m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high!
if (BuildCommDCB(szBaud, &m_dcb))
{
if (SetCommState(m_hComm, &m_dcb))
; // normal operation... continue
else
ProcessErrorMessage("SetCommState()");
}
else
ProcessErrorMessage("BuildCommDCB()");
}
else
ProcessErrorMessage("GetCommState()");
}
else
ProcessErrorMessage("SetCommMask()");
}
else
ProcessErrorMessage("SetCommTimeouts()");

delete [] szBaud;

// flush the port
PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

// release critical section
LeaveCriticalSection(&m_csCommunicationSync);

TRACE("Initialisation for communicationport %s completed.\nUse Startmonitor to communicate.\n", sport);//portnr);

return TRUE;
}

//
// The CommThread Function.
//
UINT CSerialPortEx::CommThread(LPVOID pParam)
{
// Cast the void pointer passed to the thread back to
// a pointer of CSerialPortEx class
CSerialPortEx *port = (CSerialPortEx*)pParam;//参数传递CSerialPortEx的指针

// Set the status variable in the dialog class to
// TRUE to indicate the thread is running.
port->m_bThreadAlive = TRUE;//TRUE表示辅助线程正在运行

// Misc. variables
DWORD BytesTransfered = 0;
DWORD Event = 0;
DWORD CommEvent = 0;
DWORD dwError = 0;
COMSTAT comstat;
BOOL bResult = TRUE;

// 清除缓冲区
if (port->m_hComm) // check if the port is opened
PurgeComm(port->m_hComm,
PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

// begin forever loop. This loop will run as long as the thread is alive.
for (;;)
{

// Make a call to WaitCommEvent(). This call will return immediatly
// because our port was created as an async port (FILE_FLAG_OVERLAPPED
// and an m_OverlappedStructerlapped structure specified). This call will cause the
// m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to
// be placed in a non-signeled state if there are no bytes available to be read,
// or to a signeled state if there are bytes available. If this event handle
// is set to the non-signeled state, it will be set to signeled when a
// character arrives at the port.

// we do this for each port!

//等待SetCommMask(m_hComm,dwCommEvents),
//其中InitPort中DWORD dwCommEvents = EV_RXCHAR | EV_CTS,即接收到一字符并放入缓冲区
//和CTS(清除发送)信号改变状态   EV_CTS是否无用??????????
bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);

if (!bResult)
{
// If WaitCommEvent() returns FALSE, process the last error to determin
// the reason..
switch (dwError = GetLastError())
{
case ERROR_IO_PENDING:
{
// 串口没有数据时的正常返回值,不动作,继续
break;
}
case 87:
{
// 在WINDOWS NT下,该值将会返回,原因不明,但为正常返回值,不动作,继续
break;
}
default:
{
// 其他返回值表示有错误发生
port->ProcessErrorMessage("WaitCommEvent()");
break;
}
}
}
else
{
// If WaitCommEvent() returns TRUE, check to be sure there are
// actually bytes in the buffer to read.
//
// If you are reading more than one byte at a time from the buffer
// (which this program does not do) you will have the situation occur
// where the first byte to arrive will cause the WaitForMultipleObjects()

...全文
408 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
lidamingnew123 2019-04-21
  • 打赏
  • 举报
回复
非常感谢二位大佬的宝贵建议,我自己试了如果用CreateThread后启动线程在DLL中,调用该DLL的程序运行正常,一切OK,非常感谢二位的宝贵和大力支持,在此表示感谢!谢谢!
牧童吃五谷 2019-04-20
  • 打赏
  • 举报
回复
这个程序例子以前好像看过,对于线程发送消息采用了函数SendMessage(...)发送消息,这个是有问题的
zgl7903 2019-04-19
  • 打赏
  • 举报
回复
AfxBeginThread 前设置个断点 调试进去看看, 是不是有什么奔溃了? DLL 个人建议使用 CreateThread API

15,471

社区成员

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

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