关于线程的问题(100分)

  • 主题发起人 主题发起人 南来北往
  • 开始时间 开始时间

南来北往

Unregistered / Unconfirmed
GUEST, unregistred user!
我用API函数实现串口的接收发送数据,既可以接受又可以发送数据,接收是通过线程实现
的,但是我单击发送数据的命令按钮后,接收的的线程就不再工作了,这是怎么回事,请
各位指点迷津,谢谢!!
 
你应当使你的接受线程处于循环状态,用来接受信息,你可以调试一下,你的接受线程是正常终止了还是异常退出。
 
如果光是接收的话,线程完全正确,对方每次发送的数据均能收到,但是我向下位机发送
数据后,接收线程就像被挂起,需要再次execute。
 
为什么要用Execute??
 
你创建线程时是怎么创建的?
如果创建时挂起了,需要执行时是调用Resume而不是Execute,你调用Execute是没有用的,它还是在主线程中执行的。所以就被阻塞了。
 
线程执行execute完毕之后就结束了。所以要反复处理的话execute中必须有循环,另外你不能自己调用execute方法,execute是线程自己调用的,不需要你来处理。
 
下面是我的程序,请各位帮忙看看,谢谢!
unit MainFrm;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,comctrls, ExtCtrls, Buttons;

const
WM_COMMNOTIFY=WM_USER+365;

type
TRecvThread=Class(TThread)
public
procedure Execute;override;
end;

TMainForm = class(TForm)
Panel1: TPanel;
Label4: TLabel;
edtSend: TEdit;
SendBt: TButton;
CloseBt: TButton;
CancleBt: TButton;
stbSend: TStatusBar;
mmoSend: TMemo;
OpenBt: TButton;
GroupBox1: TGroupBox;
CmbSendComm: TComboBox;
Label2: TLabel;
Label3: TLabel;
cmbSendBaudRate: TComboBox;
Label5: TLabel;
cmbSendStopBits: TComboBox;
Label6: TLabel;
cmbSendParity: TComboBox;
RecvBt: TButton;
CheckBox1: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure OpenBtClick(Sender: TObject);
procedure SendBtClick(Sender: TObject);
procedure RecvBtClick(Sender: TObject);

private
procedure CommInitialize(comm:string;BaudRate:integer;StopBits:byte;Parity:byte);
procedure WMCOMMNOTIFY(var Message:TMessage);Message WM_COMMNOTIFY; //数据接收信息处理函数
{ Private declarations }
public
{ Public declarations }
end;

var
MainForm: TMainForm;
Post_Event:Thandle; //创建事件同步对象的句柄
hSend:THandle; //发送串口的句柄
Read_os:Toverlapped; //重叠结构的变量
Receive:boolean; //开关变量,代表是否接受
implementation

{$R *.dfm}

PROCEdure tmainform.CommInitialize(comm:string;BaudRate:integer;StopBits:byte;Parity:byte);
var
dcb:TDCB;
Error:boolean;
CommTimeOut:TCOMMTIMEOUTS;
begin
hSend:=createfile(Pchar(comm),GENERIC_WRITE or GENERIC_READ ,0,NIL,OPEN_EXISTING,
FILE_FLAG_OVERLAPPED ,0); //打开串口 OR GENERIC_READ or FILE_ATTRIBUTE_NORMAL
IF hSend=INVALID_HANDLE_VALUE then
raise Exception.Create('打开'+comm+'端口错误!');

commtimeout.ReadIntervalTimeout:=MAXDWORD;
COMmtimeout.ReadTotalTimeoutMultiplier:=0;
commtimeout.ReadTotalTimeoutConstant:=1000;
commtimeout.WriteTotalTimeoutMultiplier:=2;
commtimeout.WriteTotalTimeoutConstant:=1000;
setcommtimeouts(hSend,commtimeout); //设置超时


SetupComm(hSend,4096,4096); //设置输入和输出缓冲区大小

//设置串口的波特率、字符位数、奇偶校验、停止位
GetCommState(hSend,dcb);
dcb.BaudRate:=BaudRate;
dcb.ByteSize:=8;
dcb.StopBits:=StopBits;
dcb.Parity:=Parity;
Error:=SetCommState(hSend,dcb);
if (not Error) then
raise Exception.Create('设置'+comm+'错误!');

Error:=SetCommMask(hSend,EV_RXCHAR);
IF not Error then
raise exception.Create('SetCommMask错误!');
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
cmbsendcomm.ItemIndex:=0;
cmbsendbaudrate.ItemIndex:=0;
cmbsendstopbits.ItemIndex:=1;
cmbsendparity.ItemIndex:=0;
end;

procedure TMainForm.OpenBtClick(Sender: TObject);
var
recvThread:TRecvThread;
begin
CommInitialize('com2',9600,ONESTOPBIT,NOPARITY);
STBsend.Panels[0].Text:='串口已打开...';
end;

procedure TMainForm.SendBtClick(Sender: TObject);
var
dwNumberOfBytesWritten,dwNumberOfBytesToWrite,ErrorFlag,dwWhereToStartWriting:DWORD;
pDataToWrite:PChar;
write_os:Toverlapped;
begin
dwWhereToStartWriting:=0;
dwNumberOfBytesWritten:=0;
//设置将要向串口写的数据长度
dwNumberOfBytesToWrite:=edtSend.GetTextLen;
if (dwNumberOfBytesToWrite=0) then
raise exception.Create('发送缓冲区为空!');
//将mmoSend中的文本传到pDateToWrite缓冲区
pDataToWrite:=pchar(trim(edtSend.Text));
fillchar(write_os,sizeof(write_os),0);
//位重叠创建事件
write_os.hEvent:=createevent(nil,true,true,nil);
//设置直到最后一个字符被发送
setCommMask(hSend,EV_TxEMPTY);
Repeat
//发送数据
if not WriteFile(hSend,pdataToWrite[dwWhereToStartWriting],dwNumberOfBytesToWrite,dwNumberOfBytesWritten,
@write_os) then
begin
errorFlag:=GetLastError;
if ErrorFlag<>0 then
begin
if ErrorFlag=ERROR_IO_PENDING THEN
begin
WaitForSingleObject(Write_os.hEvent,INFINITE);
GetOverlappedResult(hSend,write_os,dwNumberOfBytesWritten,False);
end
else raise exception.Create('发送数据失败!');
end;
end;
//减去已发生的数据长度
dec(dwNumberOfBytesToWrite,dwNumberOfBytesWritten);
//记录已发送的数据长度
inc(dwWhereToStartWriting,dwNumberOfBytesWritten);
until(dwNumberOfBytesToWrite<=0);
mmoSend.Lines.Add('已发送:'+inttostr(dwWhereToStartWriting)+'个字节的数据');
end;

procedure TMainForm.RecvBtClick(Sender: TObject);
var
recvThread:TRecvThread;
begin
FillChar(Read_os,Sizeof(Read_os),0);
Read_os.Offset:=0;
Read_os.OffsetHigh:=0;
//创建Ovrelapped事件
Read_os.hEvent:=createEvent(nil,true,false,nil);
if read_os.hEvent=null then
begin
closehandle(hSend);
raise exception.Create('Create Event Error');
end;
Post_event:=createevent(nil,true,true,nil);
if post_event=null then
begin
closehandle(hSend);
closehandle(read_os.hEvent);
raise exception.Create('Create Event Error');
end;
//建立通信监视线程
recvThread:=TRecvThread.Create(false);
//发送DTR信号
EscapeCommFunction(hSend,SETDTR);

stbSend.Panels[1].Text:='正在接收数据...';
stbSend.Refresh;
end;

procedure TrecvThread.Execute; //接收串口述句的线程执行体
var
dwEvtMask,dwTranser:DWORD;
wait,Ok:boolean;
Os:Toverlapped;
begin
FreeOnTerminate:=true;
Receive:=true;
FillChar(os,Sizeof(os),0);
os.hEvent:=createevent(nil,true,false,nil);
if os.hEvent=null then
begin
MessageBox(0,'os.Event Create Error!','Notice',MB_OK);
exit;
end;
if (not setcommMask(hSend,EV_RXCHAR)) THEN
BEGIN
messagebox(0,'setcommMask Error','Notice',MB_OK);
END;
while(receive) do
begin
dwEvtMask:=0;
//等待事件发生
if not waitcommevent(hSend,dwEvtMask,@os) then
begin
if ERROR_IO_PENDING=GetLastError then
GetOverLappedResult(hSend,Os,dwTranser,True);
end;
if ((dwEvtMask and EV_RXCHAR)=EV_RXCHAR) THEN
begin
waitforsingleobject(post_event,INFINITE);
ResetEvent(post_event);
ok:=postmessage(mainform.Handle,WM_COMMNOTIFY,hSend,0);
if (not ok) then
begin
messagebox(0,'PostMessage Error','Notice',MB_OK);
exit;
end;
end;
end;
closehandle(os.hEvent);
end;

procedure tmainform.WMCOMMNOTIFY(var message:tmessage);
var
CommState:ComStat;
dwNumberOfBytesRead:DWORD;
ErrorFlag:DWORD;
InputBuffer:array[0..100] of char;
begin
if not clearcommerror(hSend,ErrorFlag,@Commstate) then
begin
messagebox(0,'clearcommerror','Notice',MB_OK);
purgecomm(hSend,Purge_Rxabort or Purge_Rxclear);
exit;
end;
if (commstate.cbInQue>0) then
begin
fillchar(inputbuffer,commstate.cbInQue,#0);
if not readfile(hSend,InputBuffer,Commstate.cbInQue,dwNumberOfBytesRead,@read_os) then
begin
ErrorFlag:=GetLastError;
if (ErrorFlag<>0) and (ErrorFlag<>ERROR_IO_PENDING) THEN
begin
receive:=false;
raise exception.Create('读串口数据出错!');
end
else begin
waitforsingleobject(hSend,INFINITE);
GETOVERlappedresult(hSend,read_os,dwnumberofbytesread,false);
end;
end;
if dwnumberofbytesread>0 then
begin
read_os.Offset:=read_os.Offset+dwNumberofbytesread;
inputbuffer[dwnumberofbytesread]:=#0;;
mmosend.Lines.Add('接收到:'+inttostr(dwnumberofbytesread)+'个字节的数据');
mmosend.Lines.Add(strpas(inputbuffer));
end;
end;
setevent(post_event);
end;

end.

 
你因该把和通讯相关的部分写到thread中。
包括:CommInitialize,Receive,Send.
 
多人接受答案了。
 
后退
顶部