請教有關Mail Queue實作問題? |
尚未結案
|
jeffxx
一般會員 發表:7 回覆:22 積分:5 註冊:2003-10-10 發送簡訊給我 |
MailQue實作問題 Q1:我用了下面的方式做了一個mailque請問我需要對信箱做同步嗎?
(我假設Q2是會有問題的所以才做了一個信箱讓一個人來送信)
Q2:如果我讓寄信的人共用一組送信元件會有問題嗎?還是要用很多組才能正常動作 以下的程式包含四個部分:信、信箱、寄信者、送信者
送信的人從0的位置取信並刪除信件
寄信的人做addobject會加在最後一個位置 (1)信
TAlertMail = class
private
public
mailTime: string;
name:string;
subject: string;
sendmessage: string;
end; (2)信箱(只有一個信箱)
formMain.mailque:TStringList; (3)寄信的人(執行緒,會有很多人)
在事件發生時進行下面動作
mail := TAlertMail.Create;
mail.mailTime := FormatDateTime('yyyymmddhhnnss', Now);
mail.name :='jeff' ;
mail.subject :='jeff found Error';
mail.sendmessage := 'jeff found Error at ' mail.mailTime;
formMain.mailque.AddObject('', mail);
|
jeffxx
一般會員 發表:7 回覆:22 積分:5 註冊:2003-10-10 發送簡訊給我 |
(4)送信的人(執行緒,只有一個人,不斷檢查信箱)
type TSendMail = class(TThread) private { Private declarations } protected mailFrom: string; mailTo: string; procedure Execute; override; public constructor Create(mFrom, mTo: string); end; implementation uses unitMain; constructor TSendMail.Create(mFrom, mTo: string); begin inherited Create(False); mailFrom := mFrom; mailTo := mTo; end; procedure TSendMail.Execute; var mail: TAlertMail; memo: TStringList; begin { Place thread code here } memo := TStringList.Create; //判斷是否還有信 while (true) do begin Sleep(2500); if (formMain.mailque.Count > 0) then begin while (formMain.mailque.Count > 0) do begin if (formMain.mailque.Objects[0] is TAlertMail) then begin //取回信件 mail := (formMain.mailque.Objects[0] as TAlertMail); memo.Clear; memo.Add(mail.name); memo.Add(mail.sendmessage); with formMain.IdMsgMail do begin From.Name := 'AlertModule'; From.Address := Trim(mailFrom); Recipients.EMailAddresses := Trim(mailTo); Subject := mail.subject; Body.Assign(memo); end; with formMain.IdSMTPMail do begin Connect; try Send(formMain.IdMsgMail); finally Disconnect; end; end; mail.Free; formMain.mailque.Delete(0); end else begin formMain.mailque.Objects[0].Free; formMain.mailque.Delete(0); end; end; end; end; memo.Free; end; end.ps:我有縮排貼上來都會不見推建用下面的軟體排版~ http://www.dow.wau.nl/aew/delforexp.html 會縮排了malanlk 謝啦 發表人 - jeffxx 於 2005/08/01 11:45:23 發表人 - jeffxx 於 2005/08/01 13:43:34 |
malanlk
尊榮會員 發表:20 回覆:694 積分:577 註冊:2004-04-19 發送簡訊給我 |
|
malanlk
尊榮會員 發表:20 回覆:694 積分:577 註冊:2004-04-19 發送簡訊給我 |
|
jeffxx
一般會員 發表:7 回覆:22 積分:5 註冊:2003-10-10 發送簡訊給我 |
|
malanlk
尊榮會員 發表:20 回覆:694 積分:577 註冊:2004-04-19 發送簡訊給我 |
如果元件本身 是 Thread safe 表示當它存取內部變數時都會做同步控制.
如果元件本身沒有說明是否 Thread safe 最好的辦法就是殺到原始碼內部去看. 在 Classes.pas 這個單元中有 TStringList.InsertItem(...)及TStringList.AddObject(....) 這是你呼叫 AddObject 時會作的程序.
function TStringList.AddObject(const S: string; AObject: TObject): Integer; begin if not Sorted then Result := FCount else if Find(S, Result) then case Duplicates of dupIgnore: Exit; dupError: Error(@SDuplicateString, 0); end; InsertItem(Result, S, AObject); end; procedure TStringList.InsertItem(Index: Integer; const S: string; AObject: TObject); begin Changing; if FCount = FCapacity then Grow; if Index < FCount then System.Move(FList^[Index], FList^[Index 1], (FCount - Index) * SizeOf(TStringItem)); with FList^[Index] do begin Pointer(FString) := nil; FObject := AObject; FString := S; end; Inc(FCount); Changed; end;假設 你在呼叫 AddObject 時 呼叫到 InsertItem 並傳入 FCount 好巧不巧 送信的 thread 在這當下連續成功發出 2封信, 所以 FCount 就被遞減兩次 再回到 InsertItem 來看 Index 的值肯定大於 FCount 而你認為 FList^[Index] 會指到哪裡....... |
jeffxx
一般會員 發表:7 回覆:22 積分:5 註冊:2003-10-10 發送簡訊給我 |
改成這樣可以嗎? 另外有個問題可以問一下嗎 雖然我標是mail(但不一定要用網路寄信,我指的是寄信的概念) 這是問thread跟oo的東西不太懂為什麼要放在網路區說 我還以為我發言不當文章被刪了~ (1)信 TAlertMail = class private public mailTime: string; name:string; subject: string; sendmessage: string; end; (2)信箱(只有一個信箱) formMain.mailque:TStringList; formMain.mailmutex: THandle; OnCreate mailmutex:=CreateMutex(nil, False,'MailMutex'); mailque := TStringList.Create; OnDestroy WaitForSingleObject(mailmutex, INFINITE); CloseHandle(mailmutex); (3)寄信的人(執行緒,會有很多人) 在事件發生時進行下面動作 mail := TAlertMail.Create; mail.mailTime := FormatDateTime('yyyymmddhhnnss', Now); mail.name :='jeff' ; mail.subject :='jeff found Error'; mail.sendmessage := 'jeff found Error at ' mail.mailTime; WaitForSingleObject(formMain.mailmutex, INFINITE); formMain.mailque.AddObject('', mail); ReleaseMutex(formMain.mailmutex) ; |
jeffxx
一般會員 發表:7 回覆:22 積分:5 註冊:2003-10-10 發送簡訊給我 |
(4)送信的人(執行緒,只有一個人,不斷檢查信箱) type TSendMail = class(TThread) private { Private declarations } protected mailFrom: string; mailTo: string; procedure Execute; override; public constructor Create(mFrom, mTo: string); end; implementation uses unitMain; constructor TSendMail.Create(mFrom, mTo: string); begin inherited Create(False); mailFrom := mFrom; mailTo := mTo; end; procedure TSendMail.Execute; var mail: TAlertMail; memo: TStringList; begin { Place thread code here } memo := TStringList.Create; //判斷是否還有信 while (true) do begin Sleep(2500); if (formMain.mailque.Count > 0) then begin while (formMain.mailque.Count > 0) do begin if (formMain.mailque.Objects[0] is TAlertMail) then begin //取回信件 WaitForSingleObject(formMain.mailmutex, INFINITE); mail := (formMain.mailque.Objects[0] as TAlertMail); formMain.mailque.Delete(0); ReleaseMutex(formMain.mailmutex) ; memo.Clear; memo.Add(mail.name); memo.Add(mail.sendmessage); with formMain.IdMsgMail do begin From.Name := 'AlertModule'; From.Address := Trim(mailFrom); Recipients.EMailAddresses := Trim(mailTo); Subject := mail.subject; Body.Assign(memo); end; with formMain.IdSMTPMail do begin Connect; try Send(formMain.IdMsgMail); finally Disconnect; end; end; mail.Free; end else begin WaitForSingleObject(formMain.mailmutex, INFINITE); formMain.mailque.Objects[0].Free; formMain.mailque.Delete(0); ReleaseMutex(formMain.mailmutex) ; end; end; end; end; memo.Free; end; end. formatter:http://www.dow.wau.nl/aew/delforexp.html reference:The Tomes of Delphi 3: Win32 Core API Help File by Larry Diehl |
malanlk
尊榮會員 發表:20 回覆:694 積分:577 註冊:2004-04-19 發送簡訊給我 |
|
jeffxx
一般會員 發表:7 回覆:22 積分:5 註冊:2003-10-10 發送簡訊給我 |
我試了一下TCriticalSection為什麼我把同步mark掉程式還會同步 (1)主程式在Button1Click啟動執行緒
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, SyncObjs; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public cs: TCriticalSection; counter: Integer; { Public declarations } end; var Form1: TForm1; cnt:Integer; implementation uses Unit2; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var i: Integer; begin cnt:=0; counter := 0; for i := 1 to 500 do begin TCounterThread.Create(false); end; end; procedure TForm1.Button2Click(Sender: TObject); begin showmessage(IntToStr(cnt)); showmessage(IntToStr(counter)); end; procedure TForm1.FormDestroy(Sender: TObject); begin cs.Destroy; end; procedure TForm1.FormCreate(Sender: TObject); begin cs := TCriticalSection.Create; end; end.(2)執行緒 unit Unit2; interface uses Classes, SysUtils,SyncObjs; type TCounterThread = class(TThread) private { Private declarations } protected procedure Execute; override; end; implementation uses Unit1; procedure TCounterThread.Execute; var i: Integer; begin { Place thread code here } for i := 1 to 500 do begin sleep(1); //form1.cs.Enter; <=====為什麼我把這拿掉還有同步效果 try cnt:=cnt 1; form1.counter:=form1.counter 1; finally //form1.cs.Leave; <=====為什麼我把這拿掉還有同步效果 end; end; end; end. |
malanlk
尊榮會員 發表:20 回覆:694 積分:577 註冊:2004-04-19 發送簡訊給我 |
你那樣寫看不出是否同步吧!
有點小看 CPU 的能力 你以為 0.001 秒才算一次哦..... 用下面的程式試試 所有 Thread 迴圈執行完 應該得到 1000; 你再把 form1.cs.Enter; form1.cs.Leave; 標起來, 如果還跑的到1000就不用給我分數啦..... < class="code">
unit Unit1; interface uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SyncObjs, StdCtrls; type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
cs: TCriticalSection;
counter: Integer;
end; var
Form1: TForm1; implementation {$R *.dfm} uses Unit2; procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 1 to 50 do
begin
TCounterThread.Create(false);
end;
end; procedure TForm1.FormCreate(Sender: TObject);
begin
counter := 0;
cs := TCriticalSection.Create;
end; procedure TForm1.FormDestroy(Sender: TObject);
begin
cs.Free;
end; end. unit Unit2; interface
uses
Classes, SysUtils,SyncObjs; type
TCounterThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure IncCount(iCnt: Integer);
end; implementation uses Unit1; procedure TCounterThread.Execute;
var
i: Integer;
begin
{ Place thread code here }
for i := 1 to 20 do
begin
form1.cs.Enter; //<=====為什麼我把這拿掉還有同步效果
try
IncCount(form1.counter);
finally
form1.cs.Leave; //<=====為什麼我把這拿掉還有同步效果
end;
end;
end; procedure TCounterThread.IncCount(iCnt: Integer);
begin
Sleep(10);
form1.counter := iCnt 1;
form1.Caption := IntToStr(form1.counter);
end;
end.
|
jeffxx
一般會員 發表:7 回覆:22 積分:5 註冊:2003-10-10 發送簡訊給我 |
|
malanlk
尊榮會員 發表:20 回覆:694 積分:577 註冊:2004-04-19 發送簡訊給我 |
|
jeffxx
一般會員 發表:7 回覆:22 積分:5 註冊:2003-10-10 發送簡訊給我 |
修正版測試程式有興趣的人可以run看看~
(1)主程式
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, SyncObjs; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button3: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private declarations } public cs: TCriticalSection; counter: Integer; { Public declarations } end; var Form1: TForm1; cnt: Integer; implementation uses Unit2, Unit3; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var i: Integer; begin cnt := 0; counter := 0; for i := 1 to 6 do begin TCounterThread.Create(i); end; end; procedure TForm1.Button2Click(Sender: TObject); begin showmessage(IntToStr(counter)); end; procedure TForm1.FormDestroy(Sender: TObject); begin cs.Free; end; procedure TForm1.FormCreate(Sender: TObject); begin cs := TCriticalSection.Create; end; procedure TForm1.Button3Click(Sender: TObject); begin memo1.Clear; end; end.(2)執行緒 unit Unit2; interface uses Classes, SysUtils,SyncObjs; type TCounterThread = class(TThread) private threadId:Integer; { Private declarations } protected procedure Execute; override; public constructor Create(thrid:integer); procedure IncCounter(iCnt:Integer); end; implementation uses Unit1; constructor TCounterThread.Create(thrid: integer); begin inherited Create(False); threadId:=thrid; end; procedure TCounterThread.Execute; var i: Integer; begin for i := 1 to 50 do begin form1.cs.Enter; //想要保護的變數就放在Enter、Leave間,mark掉就可以看到差異了 try IncCounter(form1.counter); form1.Memo1.Lines.Add(IntToStr(threadId) ':' IntToStr(form1.counter)); finally form1.cs.Leave; end; end; end; procedure TCounterThread.IncCounter(iCnt: Integer); begin sleep(10); form1.counter:=iCnt 1; end; end. |
Ktop_Robot
站務副站長 發表:0 回覆:3511 積分:0 註冊:2007-04-17 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |