我有工作线程需要根据另一个线程(例如与用户交互的线程)给出的命令执行各种任务。工作者线程需要执行以下功能:处理线程之间的状态变化
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:我在应用程序级别处理用例请求可能出现的这些用例以任何顺序。一个很好的例子是相机应用程序:启动应用程序,开始预览,暂停预览,拍照,锁定屏幕,退出应用程序等。 –
所有这些用例都涉及阻止特定工作完成,而不是停止线程。当你想暂停预览时,你不关心线程在做什么,甚至不管线程是否在特定的时间执行它。这是您想要暂停的工作预览 - 无论是一个线程还是五十个线程都参与了该过程。 –