我有工作線程需要根據另一個線程(例如與用戶交互的線程)給出的命令執行各種任務。工作者線程需要執行以下功能:處理線程之間的狀態變化
a。一旦開始,工作線程需要等待用戶線程發出任務。 b。一旦給出任務,工作線程需要繼續執行任務,除非被告知不這樣做。
c。在任何時候,用戶線程都可以要求工作線程停止(退出),暫停,繼續,暫停和等待另一個任務等。
我在使用多線程程序時多次遇到此用例並通常最終使用複雜的邏輯(很多if/elses,信號量信號/等待等)
所以我想知道是否有這種用例的良好設計模式?
我有工作線程需要根據另一個線程(例如與用戶交互的線程)給出的命令執行各種任務。工作者線程需要執行以下功能:處理線程之間的狀態變化
a。一旦開始,工作線程需要等待用戶線程發出任務。 b。一旦給出任務,工作線程需要繼續執行任務,除非被告知不這樣做。
c。在任何時候,用戶線程都可以要求工作線程停止(退出),暫停,繼續,暫停和等待另一個任務等。
我在使用多線程程序時多次遇到此用例並通常最終使用複雜的邏輯(很多if/elses,信號量信號/等待等)
所以我想知道是否有這種用例的良好設計模式?
object thisLock;
bool paused;
bool exit;
void YourThread() {
while (true)
{
lock (thisLock)
{
if (exit) return;
while (paused)
Monitor.Wait(thisLock);
}
//do some work
//process one item
//whatever
}
}
暫停 -
paused = true;
取消暫停 -
lock (thisLock)
{
paused = false;
Monitor.Pulse(thisLock);
}
退出
exit = true;
的actor model可能是一個不錯的選擇在這些情況下。我正在研究Akka toolkit,您可以閱讀關於使用documentation中的演員構建軟件的更多信息。爲了讓你對你所描述的工人實體怎麼可能看起來像,考慮下面的代碼一些印象(Scala寫的,而是應該由它本身是描述):
trait State
case object Idle extends State // marker object for the no-work state
case object Active extends State // marker object for when there is work to do
case object Paused extends State // marker for when work is known but paused
class Worker extends Actor extends FSM[State, Option[Work]] {
startWith(Idle, None) // start out with no work to do
when(Idle) {
case Event(DoWork(workPackage), _) =>
self ! KickMe // message sent to this actor to make it perform some work
goto(Active) using Some(workPackage)
}
when(Active) {
case Event(KickMe, Some(work)) =>
execute(work)
self ! KickMe // this keeps the work going until told otherwise
stay()
case Event(Pause, _) =>
goto(Paused)
}
when(Paused) {
// KickMe messages are ignored in this state, leading to a pause
case Event(Resume, _) =>
self ! KickMe
goto(Active)
}
whenUnhandled { // these cases apply in all three states
case Event(Stop, _) =>
stop()
case Event(DropIt, _) =>
goto(Idle) using None // zero out the current work package
}
def execute(work: Work) = ... // whatever there is to do
}
然後,您可以用這樣的state machine互動通過發送消息:
// initialize Akka
val system = ActorSystem("demo")
// instantiate the actor, returning an ActorRef
val workerRef = system.actorOf(Props[Worker], name = "Fred")
// send the first work package to get it going
workerRef ! DoWork(new MyWork(...)) // whatever the work package
... // after some time
workerRef ! Pause
... // and then even later maybe
workerRef ! Resume
... // and finally
workerRef ! Stop
實現上面沒有100%防彈(因爲我希望把重點放在展示的一般原則),而且它也沒有在阿卡寫這樣的事情的唯一途徑。重要的部分是你不明確地管理線程,你只管理你的actor,Akka會小心地在線程上運行它們並在它們之間安全地傳遞消息。如果這看起來有趣,請隨時查詢有關mailing list的更多信息。
你的邏輯很可能很複雜,因爲你試圖讓一個實體做太多的工作(這會導致O(N!)的複雜性)。
如果您將線程安全策略(線程安全/不安全隊列,同步點,標誌等)與其他行爲方面一起使用,那麼工作人員和策略都將是緊湊的可重用Lego乾淨設計模塊。
下面我發佈一個方法的標題 - 它幫助我爲前提,while循環:
private static final boolean conditionMet (
final boolean isEventDispatchThread
, final List<AWTEvent> pendingEvents
, final AtomicBoolean isDefaultEventQueue
, final AtomicBoolean isEventQueueChanging
, final AtomicReference<DispatchableEventQueue> newEventQueue
, final AtomicReference<ProgressMonitor> processMessageBlocking
, final AtomicInteger actionsRemaining
, final AtomicBoolean interruptAction
, final AtomicReference<Tuple2<IAction, Throwable>> throwableWasThrownFromChain
, final ConcurrentHashMap<IAction, Boolean> valuesReadyToBeSetFromEDT
, final ConcurrentHashMap<IAction, Boolean> valuesWasSetFromEDT
, final ConcurrentHashMap<IAction, Boolean> onSwingReadyToBeRunFromEDT
, final ConcurrentHashMap<IAction, Boolean> onSwingWasActuallyRunFromEDT
, final FlexReference<Map<String, Object>> remoteRef
) throws InterruptedException {
我可能還是想知道,如果這是一個很好的設計模式,但是通過使用狀態機或而不是,如果你試圖在一個地方保持簡單的話(while),那麼在一個不同的地方(條件)就不難得到更大的混亂。對我而言,這是一個更高層次的程序,並且理所當然,所有這些超時,而不是可用性和死亡。
這實在是一個非常不尋常的情況,並不典型。一般來說,如果你需要做的工作,你就可以做到。不得不停下來,暫停,繼續或等待是非常不尋常的。我已經編寫了十多年的多線程程序,並且從未做過任何這些事情。 (除了等待工作時,幾乎沒有任何事情可做,但這是基本工作調度機制的一部分,而不是額外的事情。) –
@DavidSchwartz:我在應用程序級別處理用例請求可能出現的這些用例以任何順序。一個很好的例子是相機應用程序:啓動應用程序,開始預覽,暫停預覽,拍照,鎖定屏幕,退出應用程序等。 –
所有這些用例都涉及阻止特定工作完成,而不是停止線程。當你想暫停預覽時,你不關心線程在做什麼,甚至不管線程是否在特定的時間執行它。這是您想要暫停的工作預覽 - 無論是一個線程還是五十個線程都參與了該過程。 –