2012-03-02 34 views
5

我正在處理這種類型的動作隊列線程,我想等待某個動作被執行。我想在主線程中創建動作,然後將其傳遞給隊列線程函數(到隊列末尾)並等待執行此動作。所以我需要區分我剛纔查詢的行爲已經執行並等待它。將事件從主線程傳遞給工作線程並等待它是否安全?

我有一個以下(僞)代碼,我想知道

  • 是否與Windows事件對象的線程安全的工作?
  • 如果是的話,這個概念會有效嗎?

type 
    TMyThread = class(TThread); 
    private 
    FEvent: THandle; 
    protected 
    procedure Execute; override; 
    public 
    procedure DoSomething(const AEvent: THandle); 
    end; 

procedure TMyThread.Execute; 
begin 
    // is it working with events thread safe ? 
    SetEvent(FEvent); 
    // the thread will continue, so I can't use WaitFor 
    // but it won't set this specific FEvent handle again 
    // I'm working on such kind of an action queue, so once the action with ID, 
    // here represented by the FEvent will be processed, it's removed from 
    // the action queue 
end; 

procedure TMyThread.DoSomething(const AEvent: THandle); 
begin 
    FEvent := AEvent; 
end; 

// here's roughly what I want to do 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    OnceUsedEvent: THandle; 
begin 
    // the thread is already running and it's instantiated in MyThread 
    // here I'm creating the event for the single request I need to be performed 
    // by the worker thread 
    OnceUsedEvent := CreateEvent(nil, True, False, nil); 
    try 
    // here I'm passing the event handle to the worker thread (like a kind of 
    // a request ID) 
    MyThread.DoSomething(OnceUsedEvent); 
    // and here I want to wait for 10 seconds (and also interrupt this waiting 
    // when the user closes the application if possible ?) for the thread if 
    // performs my request 
    WaitForSingleObject(OnceUsedEvent, 10000); 
    finally 
    // close the event handle 
    CloseHandle(OnceUsedEvent); 
    end; 
    // and continue with something else 
end; 

謝謝!

+0

在按鈕事件處理程序中等待事件將阻止主線程,所以這不是你想要的!也許你可以使用事件代替(線程完成時調用) – jpfollenius 2012-03-02 15:43:57

+2

這樣的等待不會做你想做的事。它不能被打斷。你爲什麼要阻止10秒?這很奇怪。 – 2012-03-02 15:50:21

+0

理想無限;這是重命名行動。我需要進入VirtualTreeView節點的編輯模式並保持編輯器處於活動狀態,直到從線程獲得重命名操作的結果(我有一個額外的事件處理程序,如果重命名成功並且我退出時需要傳遞結果這個事件處理程序編輯器被隱藏)。 – 2012-03-02 16:02:29

回答

4

是的,那很好。從CreateEvent返回的句柄可以被所有線程自由使用。其他任何東西都會使它變得毫無用處,因爲這是它的主要用途:)

+1

不一定。我認爲句柄可能是線程特定的,或者至少不是線程安全的。如果另一個線程想要訪問同一個事件,可能需要調用DuplicateHandle,或者需要使用相同的事件名稱來調用CreateEvent本身。 – 2012-03-02 16:24:11

+0

經驗上,句柄可以用於其他線程 - 我經常以這種方式使用事件。 – 2012-03-02 17:48:25

+0

@RobKennedy這正是我一直在做的事情,直到今天,當我看到一個例子,有人剛剛有兩個線程使用相同的句柄變量... – 2015-04-01 23:08:54

3

不要等待GUI事件處理程序中的線程。不要等待事件,信號量或互斥量,sleep()循環,DoEvents循環或其任何組合。

如果您想與主線程進行通信以表示線程池中已經處理了某些內容,請查看PostMessage()API。

+0

當與主花紋溝通時使用'PostMessage'的替代方法是1)'Thread .Queue'如此處所述[synchronize-and-queue-with-parameters](http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/#more-135 )(這對於FireMonkey應用程序非常有用),或者2)使用「線程安全隊列」並使用定時器循環從主線程輪詢隊列。 – 2012-03-03 13:05:26

+0

'synchronize-and-queue-with-parameters'是OK-ish,但是它會進行兩次系統調用,以找出它正在運行的線程:(使用定時輪詢定時器可以週期性地顯示最新的線程,日期值是很多變量的值,但是如果用於輪詢隊列則會引入延遲。 – 2012-03-03 14:50:47