想請教個問題,對于Delphi編程,如果對多個事件的處理程序中,都呼叫同一個用戶自己撰寫的函式的話,假如第一個事件中正在呼叫function1函式,這時有第二個事件被觸發,繼而轉向第二個事件處理程序中,如果第二個事件程序里面也呼叫function1函式的話,由function1函式計算的結果就不對。如果要是有多個事件,而且有可能會在第一個事件呼叫某一函式還未退出此函式的時候,第二個事件,又會呼叫這個函式的話,有什么解決辦法嗎?還是說,需要撰寫多個同樣功能的function1函式,起不同名稱,不同事件呼叫不同名稱?
類似下面代碼:
uj5u.com熱心網友回復:
代碼為://××××××××××××××××××××××××××
// CalCRC16用于計算CRC16校驗碼
// 多項式公式為X16+X15+X2+1
//××××××××××××××××××××××××××
function CRC16(AData:array of Byte;AStart,AEnd:Integer):Word;
const
GENP=$A001; //多項式公式X16+X15+X2+1(1100 0000 0000 0101)
var
crc:Word;
i:Integer;
tmp:Byte;
procedure CalOneByte(AByte:Byte); //計算1個位元組的校驗碼
var
j:Integer;
begin
crc:=crc xor AByte; //將資料與CRC暫存器的低8位進行異或
for j:=0 to 7 do //對每一位進行校驗
begin
tmp:=crc and 1; //取出最低位
crc:=crc shr 1; //暫存器向右移一位
crc:=crc and $7FFF; //將最高位置0
if tmp=1 then //檢測移出的位,如果為1,那么與多項式異或
crc:=crc xor GENP;
crc:=crc and $FFFF;
end;
end;
begin
crc:=$FFFF; //將余數設定為FFFF
for i:=AStart to AEnd do //對每一個位元組進行校驗
CalOneByte(AData[i]);
Result:=crc;
end;
//此程序為定時器定時3s的觸發事件,事件中呼叫CRC16函式
procedure TForm1.Timer1Timer(Sender: TObject);
var
incrc:WORD;
begin
incrc:=CRC16(txBuffer,LOW(txBuffer),4-1);
end;
//按鈕1的事件觸發函式:里面呼叫CRC16函式
procedure TForm1.Button1Click(Sender: TObject);
var
sanF:WORD;
begin
sanF:=CRC16(rxBuffer,LOW(txBuffer),4-1);
end;
類似這樣的代碼
uj5u.com熱心網友回復:
系統會為ontimer 和 buttonclick的訊息進行排序,這里的crc16運算不是并發的,總能分出先后除非在執行緒中執行,須考慮執行緒安全性
uj5u.com熱心網友回復:
可是如果ontimer訊息呼叫crc16函式的還未退出的時候,觸發了buttonclick事件,在buttonclick事件中再次呼叫crc16函式的時候,計算的值就是錯的。請問這個是什么問題?uj5u.com熱心網友回復:
就你給的代碼來看,Timer事件觸發在執行程序中,是不會回應Btuuon.Click的,因此你的這個代碼不存在重入問題,那肯定是其他地方有問題了,比如txBuffer在什么地方處理的,怎么處理的,等uj5u.com熱心網友回復:
哦,貼個我寫的程式,上面的代碼只是個說明問題的代碼。程式中使用了,SPCOMM串口控制元件,定時器控制元件。定時器會每隔3s觸發事件,進入Timer1Timer()程序利用SPCOMM的發送函式,通過串口將資料發出;同時下位機也會向串口發送資料,串口接收到資料時,SPCOMM就會進入Comm1ReceiveData()程序中,這個時候就會呼叫crc函式,但是計算的結果是錯的。
代碼如下:
function Managemessage(mbufferlength :WORD):word;
var
i,j:integer;
zhengfu:shortint;
test1,test2:integer;
crccompare1,crccompare2:WORD;
aa:longint;
begin
crccompare2:=rxBuffer[mbufferlength-3]; //rxBuffer[]中最后幾個位元組資料位 CRC低位元組,CRC高位元組,$0A,$0D
crccompare2:=(crccompare2 shl 8 )or rxBuffer[mbufferlength-4];
crccompare1:=CRC16(rxBuffer,LOW(rxBuffer),mbufferlength-4-1) ;
if crccompare1<>crccompare2 then exit(0);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
incrc:WORD;
begin
txBUFFER[0]:=DeviceAddr ;
txBUFFER[1]:=byte($01); {命令號}
txBUFFER[2]:=byte($00);
txBUFFER[3]:=byte($05);
incrc:=CRC16(txBuffer,LOW(txBuffer),4-1);
txBuffer[4]:=byte(incrc);
txBuffer[5]:=byte(incrc shr 8);
senddata(6-1);{呼叫發送函式}
end;
//接收資料事件處理
procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
BufferLength: Word);
var
forDisplay: string[11];
begin
move(buffer^,pansichar(@rxBUFFER)^,bufferlength);
if Managemessage(bufferlength)<>0 then
showmessage('資料接收成功!');
end;
uj5u.com熱心網友回復:
有沒有知道了,幫忙解答下,難道需要撰寫很多相同功能,不同名的函式供呼叫嗎?uj5u.com熱心網友回復:
同一執行緒事件處理分先后,處理完前一事件才會處理下一事件。uj5u.com熱心網友回復:
只要你不是多執行緒的程式,事件函式不會出現一個沒執行完下一個就呼叫過來的情況.uj5u.com熱心網友回復:
行程, 執行緒內部的函式執行,都有先后順序的。除非你用的是多執行緒,才會需要考慮執行緒間安全性。
uj5u.com熱心網友回復:
function CRC16(AData:array of Byte;AStart,AEnd:Integer):Word;procedure CalOneByte(AByte:Byte);
procedure TForm1.Timer1Timer(Sender: TObject);
var
incrc:WORD;
begin
incrc:=CRC16(txBuffer,LOW(txBuffer),4-1);
end;
哦,貼個我寫的程式,上面的代碼只是個說明問題的代碼。
程式中使用了,SPCOMM串口控制元件,定時器控制元件。定時器會每隔3s觸發事件,進入Timer1Timer()程序利用SPCOMM的發送函式,通過串口將資料發出;同時下位機也會向串口發送資料,串口接收到資料時,SPCOMM就會進入Comm1ReceiveData()程序中,這個時候就會呼叫crc函式,但是計算的結果是錯的。
代碼如下:
function Managemessage(mbufferlength :WORD):word;
根據你所說的,你的引數應該就是指標傳遞,你用函式封好了,它還是對SPCOMM傳遞過來的BUFF進行處理的,所以,當存在重復呼叫的時候,結果應該不會正確的
本人水平有限,對SPCOMM也不是很精通,覺得最直接的辦法是先把指標的內容在ReceiveDATA中保存為非指標,再呼叫函式
另外,3s對COM口發一個資料,這個周期有沒有問題?得結合你自己的COM口設備 傳輸速度,和處理流程。個人覺得,如果在PC上對COM口這樣控制的話,溢位或崩潰是很容易的事
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/94489.html
標籤:語言基礎/算法/系統設計
