全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1725
推到 Plurk!
推到 Facebook!

請教有關Mail Queue實作問題?

尚未結案
jeffxx
一般會員


發表:7
回覆:22
積分:5
註冊:2003-10-10

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-08-01 11:13:21 IP:61.222.xxx.xxx 未訂閱
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

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-08-01 11:15:54 IP:61.222.xxx.xxx 未訂閱
(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

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-08-01 13:27:23 IP:203.69.xxx.xxx 未訂閱
你在寫發問內容時, 在程式碼前面加 
 後面加 
系統就會幫你保留縮排了, 編輯時上面有個 # 按鈕 也是一樣的功能. 發問內容送出去還是可以改, 要不要改一下啊 在你提問的頁面 發表於 - 2005/08/01 : 11:13:21... 後面應該有4個 "icon" 其中一個可以讓你再修正內容...要不要試一下...
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-08-01 13:39:02 IP:203.69.xxx.xxx 未訂閱
要做同步! 寄信, 送信的 thread 都要作, 因為他們都對信箱做異動.
jeffxx
一般會員


發表:7
回覆:22
積分:5
註冊:2003-10-10

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-08-01 13:54:38 IP:61.222.xxx.xxx 未訂閱
可以舉列如果不做同步可能會發生怎樣的問題嗎 刪的永遠指在第0的位子看起來好像沒什麼問題 會有問題是發生在addobject上嗎 你是指addobject信可能被蓋過去嗎 還是tstringlist在重建index時會有問題?
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-08-01 14:29:13 IP:203.69.xxx.xxx 未訂閱
如果元件本身 是 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

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-08-01 17:01:55 IP:61.222.xxx.xxx 未訂閱
改成這樣可以嗎?    另外有個問題可以問一下嗎
雖然我標是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

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-08-01 17:10:40 IP:61.222.xxx.xxx 未訂閱
(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

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-08-01 19:18:28 IP:203.69.xxx.xxx 未訂閱
用 TCriticalSection 比較簡單一點... Delphi 直接支援. 發表人 - malanlk 於 2005/08/01 19:24:57
jeffxx
一般會員


發表:7
回覆:22
積分:5
註冊:2003-10-10

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-08-02 11:34:26 IP:61.222.xxx.xxx 未訂閱
我試了一下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

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-08-02 13:05:59 IP:203.69.xxx.xxx 未訂閱
你那樣寫看不出是否同步吧! 有點小看 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

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-08-02 13:44:01 IP:61.222.xxx.xxx 未訂閱
謝啦太感謝了~我知道我那裡錯了!!    
procedure TCounterThread.IncCount(iCnt: Integer);
begin
  Sleep(10);  <===================delay要放在這才有效果對吧
  form1.counter := iCnt 1;
  form1.Caption := IntToStr(form1.counter);
end;
end.
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#13 引用回覆 回覆 發表時間:2005-08-02 14:14:41 IP:203.69.xxx.xxx 未訂閱
看來 你的 mail queue 應該 OK 了...
jeffxx
一般會員


發表:7
回覆:22
積分:5
註冊:2003-10-10

發送簡訊給我
#14 引用回覆 回覆 發表時間:2005-08-02 14:19:39 IP:61.222.xxx.xxx 未訂閱
修正版測試程式有興趣的人可以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

發送簡訊給我
#15 引用回覆 回覆 發表時間:2007-04-26 13:50:39 IP:000.000.xxx.xxx 未訂閱
提問者您好:


以上回應是否已得到滿意的答覆?


若已得到滿意的答覆,請在一週內結案,否則請在一週內回覆還有什麼未盡事宜,不然,
將由版主(尚無版主之區域將由副站長或站長)自由心證,選擇較合適之解答予以結案處理,
被選上之答題者同樣會有加分獎勵同時發問者將受到扣 1 分的處分。不便之處,請見諒。


有問有答有結案,才能有良性的互動,良好的討論環境需要大家共同維護,感謝您的配合。

------
我是機器人,我不接受簡訊.
系統時間:2024-05-17 14:47:52
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!