2012-08-30 60 views
0

我正在編寫一個程序,在該程序中,我需要確保調用某個特定函數不會一次在多個線程中執行。線程同步:確保函數按順序調用

在這裏,我寫了一些簡化的僞代碼,完全在我的真實程序中做了什麼。

mutex _enqueue_mutex; 
mutex _action_mutex; 
queue _queue; 
bool _executing_queue; 

// called in multiple threads, possibly simultaneously 
do_action() { 
    _enqueue_mutex.lock() 
    object o; 
    _queue.enqueue(o); 
    _enqueue_mutex.unlock(); 

    execute_queue(); 
} 

execute_queue() { 
    if (!executing_queue) { 
    _executing_queue = true; 
    enqueue_mutex.lock(); 
    bool is_empty = _queue.isEmpty(); 
    _enqueue_mutex.lock(); 
    while (!is_empty) { 
     _action_mutex.lock(); 

     _enqueue_mutex.lock(); 
     object o = _queue.dequeue(); 
     is_empty = _queue.isEmpty(); 
     _enqueue_mutex.unlock(); 

     // callback is called when "o" is done being used by "do_stuff_to_object_with_callback" also, this function doesn't block, it is executed on its own thread (hence the need for the callback to know when it's done) 
     do_stuff_to_object_with_callback(o, &some_callback); 
    } 
    _executing_queue = false; 
    } 
} 

some_callback() { 
    _action_mutex.unlock(); 
} 

從本質上講,這個想法是,_action_mutex鎖定在while循環(我應該說,lock被假定爲阻塞,直到它可以再次鎖定),並預計將在解鎖時完成回調被稱爲(上述代碼中的some_callback)。

雖然這似乎並不奏效。如果do_action被同時調用多次,會發生什麼情況,程序會被鎖定。我認爲這可能與while循環同時執行超過一次有關,但我不知道這是怎麼回事。我的方法有什麼問題嗎?有更好的方法嗎?

感謝

回答

1

一個queue是不是專門設計是多線程(多生產者多消費者)需要使用序列相同的互斥體都eneueuedequeue操作。

(如果你的queue的實施有不同的假設,請註明它在你的問題。)

_queue.isEmpty()的檢查也需要得到保護,如果dequeue操作很容易出現Time of check to time of use problem。需要

即,線
object o = _queue.dequeue();
要由_enqueue_mutex.lock();_enqueue_mutex.unlock();以及包圍。

+0

oops ...我在代碼中有這個...我在輸入僞代碼時錯過了它。我會更新我的問題。謝謝 –

+0

調試程序的第一步是添加一些'printf'語句。 – rwong

+0

好的,請不要以爲我這樣說不禮貌,但我在嘗試尋求幫助之前嘗試自行解決問題。我知道while循環因此嘗試多次執行(見問題)。此外,鎖定互斥檢查isEmpty並不能解決問題。 –

1

您可能只需要一個單一的互斥隊列。同樣,一旦你將對象出隊,你可以在鎖之外進行處理。這將防止致電do_action()掛起太久。

mutex moo; 
queue qoo; 
bool keepRunning = true; 

do_action(): 
{ 
    moo.lock(); 
    qoo.enqueue(something); 
    moo.unlock(); // really need try-finally to make sure, 
    // but don't know which language we are using 
} 

process_queue(): 
{ 
    while(keepRunning) 
    { 
     moo.lock() 
     if(!qoo.isEmpty) 
      object o = qoo.dequeue(); 

     moo.unlock(); // again, try finally needed 

     haveFunWith(o); 
     sleep(50); 
    } 
} 

然後在它自己的線程上調用process_queue()

+0

好的想法是,我可以儘可能多地添加到隊列中,並確保'haveFunWith(o)'以與開始時相同的順序完成...所以我應該能夠添加到隊列中一些'o'正在播放。順便說一句,該語言是C++和我使用的Qt,它不會拋出異常,據我所知。 –

+0

使用這種方法,事情將全部按順序開始和完成。隊列本質上是有序的,並且它們都是從單個線程處理的(假設haveFunWith()是同步的)。 –

+0

「假設haveFunWith()是同步的」它發生在我身上,我沒有提到它不是...我的壞 –