请考虑以下事项:
public class SomeService
{
public Task StartAsync()
{
return Task.Factory
.StartNew(() => DoStartup());
}
public Task StopAsync()
{
return Task.Factory
.StartNew(() => DoShutdown());
}
}
上述问题是,如果对StartAsync
或StopAsync
进行多次调用,则会创建多个任务来启动/停止服务。实际上,人们只希望一次启动一个启动/停止任务。为此,我通常会这样做:
public class SomeService
{
private readonly object startSync = new object();
private readonly object stopSync = new object();
private Task startTask;
private Task stopTask;
public Task StartAsync()
{
var startTaskLocal = this.startTask;
if (startTaskLocal != null)
{
return startTaskLocal;
}
lock (this.startSync)
{
if (this.startTask != null)
{
return this.startTask;
}
this.startTask = Task.Factory
.StartNew(() => DoStartup())
.Then(x =>
{
lock (this.stopSync)
{
this.stopTask = null);
}
});
return this.startTask;
}
}
public Task StopAsync()
{
// similar pattern to above
}
}
现在这虽然有效,但它有点难看。在我试图将这种模式封装成小而可重复的东西之前,我已经走得太远了,我想知道是否有一种已经建立的方式这样做我不知道?
PS。我通过让StartAsync
等待任何未完成的StopAsync
电话来进一步扩展这个想法,反之亦然。这意味着任何时候都只能进行一次启动或停止操作。通过任务组合很容易做到这一点。如果我能首先发现是否已经建立了完全实现上述目标的方法,那么我可以弄清楚它是否适合这种扩展行为。
答案 0 :(得分:1)
您可以使用State Machine pattern。当代码进入AsyncStart时,将状态设置为Starting
。我建议将对象的状态设置为Running
的回调。
为Stopping
,Stopped
提供相同内容。
因此,您的服务内部可能有ServiceState
个对象。在致电AsyncStart
/ AsyncStop
之前,请检查当前状态。
<强>更新强>
...... 可以的另一种方式是存储和检查Cancellation Token。有关如何使用CancellationToken
的无数样本。这只是我的头脑,而不是确认这是最好的方式。
答案 1 :(得分:1)
我终于在我的代码库中解决了这个问题,并想到我会在这里分享我的解决方案。快速解释:我有一个StateMachineTaskFactory<T>
类,其中T
定义了有效状态(通常是枚举)。此任务工厂允许您注册有效的转换(例如,转换到Started
状态,在转换过程中使用Starting
)并执行转换。它保证了状态机语义,同时保持了异步API。它基本上使我原始代码中的状态机正式化,以强大且可重用的方式实现。
首先,这是一个如何在我的问题中提供的用例中使用它的例子:
public enum ServiceState
{
Uninitialized,
Initializing,
Initialized,
Starting,
Started,
Stopping,
Stopped
}
public class SomeService
{
private readonly StateMachineTaskFactory<ServiceState> stateMachineTaskFactory;
public Service()
{
this.stateMachineTaskFactory = new StateMachineTaskFactory<ServiceState>();
this.stateMachineTaskFactory.RegisterTransition(ServiceState.Initializing, ServiceState.Initialized, this.OnInitializeAsync);
this.stateMachineTaskFactory.RegisterTransition(ServiceState.Starting, ServiceState.Started, this.OnStartAsync);
this.stateMachineTaskFactory.RegisterTransition(ServiceState.Stopping, ServiceState.Stopped, this.OnStopAsync);
}
// we don't support cancellation in our initialize API
public Task InitializeAsync()
{
return this.stateMachineTaskFactory.TransitionTo(ServiceState.Initialized);
}
public Task StartAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return this.stateMachineTaskFactory.TransitionTo(ServiceState.Started, cancellationToken);
}
public Task StopAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return this.stateMachineTaskFactory.TransitionTo(ServiceState.Stopped, cancellationToken);
}
// even though we don't support cancellation during initialization, we'll still get a cancellation token, but it will CancellationToken.None
private Task OnInitializeAsync(CancellationToken cancellationToken, object state)
{
// return a Task that performs the actual work involved in initializing
}
private Task OnStartAsync(CancellationToken cancellationToken, object state)
{
// return a Task that performs the actual work involved in starting, passing on the cancellation token as relevant
}
private Task OnStopAsync(CancellationToken cancellationToken, object state)
{
// return a Task that performs the actual work involved in stopping, passing on the cancellation token as relevant
}
}
除了上面的示例用法之外,还有更多的功能和灵活性,但它可能是正常的用例。
对于以下代码墙感到抱歉。我删除了API文档以提高可读性。我没有包含几个实用程序类,但它们非常明显。
[Serializable]
public sealed class StateTransitionForbiddenException<T> : InvalidOperationException
where T : struct
{
private readonly T targetState;
private readonly T state;
public StateTransitionForbiddenException()
{
}
public StateTransitionForbiddenException(string message)
: base(message)
{
}
public StateTransitionForbiddenException(string message, Exception innerException)
: base(message, innerException)
{
}
public StateTransitionForbiddenException(T targetState, T state)
: base("A transition to state '" + targetState + "' was forbidden by the validate transition callback.")
{
this.targetState = targetState;
this.state = state;
}
public StateTransitionForbiddenException(string message, T targetState, T state)
: base(message)
{
this.targetState = targetState;
this.state = state;
}
private StateTransitionForbiddenException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.targetState = (T)info.GetValue("TargetState", typeof(T));
this.state = (T)info.GetValue("State", typeof(T));
}
public T TargetState
{
get { return this.targetState; }
}
public T State
{
get { return this.state; }
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("TargetState", this.targetState);
info.AddValue("State", this.state);
}
}
[DebuggerDisplay("{OldState} -> {NewState}")]
public sealed class StateChangedEventArgs<T> : EventArgs
where T : struct
{
private readonly T oldState;
private readonly T newState;
public StateChangedEventArgs(T oldState, T newState)
{
this.oldState = oldState;
this.newState = newState;
}
public T OldState
{
get { return this.oldState; }
}
public T NewState
{
get { return this.newState; }
}
}
public delegate Task CreateTaskForTransitionCallback(CancellationToken cancellationToken, object state);
public delegate bool ValidateTransitionCallback<T>(T currentState)
where T : struct;
public class StateMachineTaskFactory<T> : TaskFactory
where T : struct
{
private static readonly ExceptionHelper exceptionHelper = new ExceptionHelper(typeof(StateMachineTaskFactory<>));
private readonly ConcurrentDictionary<T, TransitionRegistrationInfo> transitionRegistrations;
private readonly object stateSync;
// the current state
private T state;
// the state to which we're currently transitioning
private T? transitionToState;
// the task performing the transition
private Task transitionToTask;
public StateMachineTaskFactory()
: this(default(T))
{
}
public StateMachineTaskFactory(T startState)
{
this.transitionRegistrations = new ConcurrentDictionary<T, TransitionRegistrationInfo>();
this.stateSync = new object();
this.state = startState;
}
public event EventHandler<StateChangedEventArgs<T>> StateChanged;
public T State
{
get
{
return this.state;
}
private set
{
if (!EqualityComparer<T>.Default.Equals(this.state, value))
{
var oldState = this.state;
this.state = value;
this.OnStateChanged(new StateChangedEventArgs<T>(oldState, value));
}
}
}
public void RegisterTransition(T beginTransitionState, T endTransitionState, CreateTaskForTransitionCallback createTaskCallback)
{
createTaskCallback.AssertNotNull("factory");
var transitionRegistrationInfo = new TransitionRegistrationInfo(beginTransitionState, createTaskCallback);
var registered = this.transitionRegistrations.TryAdd(endTransitionState, transitionRegistrationInfo);
exceptionHelper.ResolveAndThrowIf(!registered, "transitionAlreadyRegistered", endTransitionState);
}
public Task TransitionTo(T endTransitionState, CancellationToken cancellationToken = default(CancellationToken), ValidateTransitionCallback<T> validateTransitionCallback = null, object state = null)
{
lock (this.stateSync)
{
if (EqualityComparer<T>.Default.Equals(this.state, endTransitionState))
{
// already in the requested state - nothing to do
return TaskUtil.FromResult(true);
}
else if (this.transitionToState.HasValue && EqualityComparer<T>.Default.Equals(this.transitionToState.Value, endTransitionState))
{
// already in the process of transitioning to the requested state - return same transition task
return this.transitionToTask;
}
else if (this.transitionToTask != null)
{
// not in the requested state, but there is an outstanding transition in progress, so come back to this request once it's done
return this.transitionToTask.Then(x => this.TransitionTo(endTransitionState, cancellationToken, validateTransitionCallback, state));
}
else if (validateTransitionCallback != null && !validateTransitionCallback(this.State))
{
// transition is forbidden, so return a failing task to that affect
var taskCompletionSource = new TaskCompletionSource<bool>();
var exception = new StateTransitionForbiddenException<T>(endTransitionState, this.State);
taskCompletionSource.TrySetException(exception);
return taskCompletionSource.Task;
}
// else, need to transition to the chosen state
TransitionRegistrationInfo transitionRegistrationInfo;
var result = this.transitionRegistrations.TryGetValue(endTransitionState, out transitionRegistrationInfo);
exceptionHelper.ResolveAndThrowIf(!result, "transitionNotRegistered", endTransitionState);
var beginTransitionState = transitionRegistrationInfo.BeginTransitionState;
var task = transitionRegistrationInfo.TaskFactory(cancellationToken, state);
exceptionHelper.ResolveAndThrowIf(task == null, "taskFactoryReturnedNull", endTransitionState);
var previousState = this.State;
this.State = beginTransitionState;
this.transitionToState = endTransitionState;
this.transitionToTask = task
.ContinueWith(
x =>
{
if (x.IsFaulted || cancellationToken.IsCancellationRequested)
{
// faulted or canceled, so roll back to previous state
lock (this.stateSync)
{
this.State = previousState;
this.transitionToState = null;
this.transitionToTask = null;
}
if (x.IsFaulted)
{
throw x.Exception;
}
cancellationToken.ThrowIfCancellationRequested();
}
else
{
// succeeded, so commit to end state
lock (this.stateSync)
{
this.State = endTransitionState;
this.transitionToState = null;
this.transitionToTask = null;
}
}
});
return this.transitionToTask;
}
}
protected virtual void OnStateChanged(StateChangedEventArgs<T> e)
{
this.StateChanged.Raise(this, e);
}
private struct TransitionRegistrationInfo
{
private readonly T beginTransitionState;
private readonly CreateTaskForTransitionCallback taskFactory;
public TransitionRegistrationInfo(T beginTransitionState, CreateTaskForTransitionCallback taskFactory)
{
this.beginTransitionState = beginTransitionState;
this.taskFactory = taskFactory;
}
public T BeginTransitionState
{
get { return this.beginTransitionState; }
}
public CreateTaskForTransitionCallback TaskFactory
{
get { return this.taskFactory; }
}
}
}
而且,为了完整性,我的单元测试:
public sealed class StateMachineTaskFactoryFixture
{
#region Supporting Enums
private enum State
{
Undefined,
Starting,
Started,
Stopping,
Stopped
}
#endregion
[Fact]
public void default_ctor_uses_default_value_for_start_state()
{
var factory = new StateMachineTaskFactory<State>();
Assert.Equal(State.Undefined, factory.State);
}
[Fact]
public void ctor_can_set_start_state()
{
var factory = new StateMachineTaskFactory<State>(State.Stopped);
Assert.Equal(State.Stopped, factory.State);
}
[Fact]
public void register_transition_throws_if_factory_is_null()
{
var factory = new StateMachineTaskFactory<State>();
Assert.Throws<ArgumentNullException>(() => factory.RegisterTransition(State.Starting, State.Started, null));
}
[Fact]
public void register_transition_throws_if_transition_already_registered()
{
var factory = new StateMachineTaskFactory<State>();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
var ex = Assert.Throws<InvalidOperationException>(() => factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true)));
Assert.Equal("A transition to state 'Started' has already been registered.", ex.Message);
}
[Fact]
public void transition_to_throws_if_no_transition_registered_for_state()
{
var factory = new StateMachineTaskFactory<State>();
var ex = Assert.Throws<InvalidOperationException>(() => factory.TransitionTo(State.Started));
Assert.Equal("No transition to state 'Started' has been registered.", ex.Message);
}
[Fact]
public void transition_to_throws_if_task_factory_returns_null()
{
var factory = new StateMachineTaskFactory<State>();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => null);
var ex = Assert.Throws<InvalidOperationException>(() => factory.TransitionTo(State.Started));
Assert.Equal("Task factory for end state 'Started' returned null.", ex.Message);
}
[Fact]
public void transition_to_returns_same_task_if_called_multiple_times_whilst_initial_task_is_still_in_progress()
{
var factory = new StateMachineTaskFactory<State>();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.Delay(TimeSpan.FromMilliseconds(250)));
var initialTask = factory.TransitionTo(State.Started);
Assert.Equal(initialTask, factory.TransitionTo(State.Started));
Assert.Equal(initialTask, factory.TransitionTo(State.Started));
Assert.Equal(initialTask, factory.TransitionTo(State.Started));
Assert.True(initialTask.Wait(TimeSpan.FromSeconds(3)));
}
[Fact]
public void transition_to_returns_completed_task_if_already_in_desired_state()
{
var factory = new StateMachineTaskFactory<State>();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
factory.TransitionTo(State.Started).Wait();
Assert.Equal(TaskStatus.RanToCompletion, factory.TransitionTo(State.Started).Status);
}
[Fact]
public void transition_to_passes_any_state_to_task_creation_function()
{
var factory = new StateMachineTaskFactory<State>();
string receivedState = null;
factory.RegisterTransition(
State.Starting,
State.Started,
(ct, o) =>
{
receivedState = o as string;
return TaskUtil.FromResult(true);
});
factory.TransitionTo(State.Started, CancellationToken.None, null, "here is the state").Wait();
Assert.Equal("here is the state", receivedState);
}
[Fact]
[SuppressMessage("Microsoft.Naming", "CA2204", Justification = "It's not a word - it's a format string!")]
public void transition_to_ensures_previous_transition_is_first_completed_before_starting_subsequent_transition()
{
var factory = new StateMachineTaskFactory<State>();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.Delay(TimeSpan.FromMilliseconds(10)));
factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.Delay(TimeSpan.FromMilliseconds(10)));
var startedAt = DateTime.MinValue;
var stoppedAt = DateTime.MinValue;
var startedTask = factory.TransitionTo(State.Started).ContinueWith(x => startedAt = DateTime.UtcNow, TaskContinuationOptions.ExecuteSynchronously);
var stoppedTask = factory.TransitionTo(State.Stopped).ContinueWith(x => stoppedAt = DateTime.UtcNow, TaskContinuationOptions.ExecuteSynchronously);
Assert.True(Task.WaitAll(new Task[] { startedTask, stoppedTask }, TimeSpan.FromSeconds(3)), "Timed out waiting for tasks to complete.");
Assert.True(stoppedAt > startedAt, "stoppedAt is " + stoppedAt.Millisecond + " and startedAt is " + startedAt.Millisecond + ", difference is " + (stoppedAt - startedAt).ToString());
}
[Fact]
public void transition_to_can_be_canceled_before_transition_takes_place()
{
var factory = new StateMachineTaskFactory<State>();
var cancellationTokenSource = new CancellationTokenSource();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
cancellationTokenSource.Cancel();
var startedTask = factory.TransitionTo(State.Started, cancellationTokenSource.Token);
try
{
startedTask.Wait();
Assert.True(false, "Failed to throw exception.");
}
catch (AggregateException ex)
{
Assert.Equal(1, ex.InnerExceptions.Count);
Assert.IsType<OperationCanceledException>(ex.InnerExceptions[0]);
}
}
[Fact]
public void transition_to_can_be_canceled()
{
var factory = new StateMachineTaskFactory<State>();
var cancellationTokenSource = new CancellationTokenSource();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.Delay(TimeSpan.FromMilliseconds(150)));
var startedTask = factory.TransitionTo(State.Started, cancellationTokenSource.Token);
startedTask.ContinueWith(x => cancellationTokenSource.Cancel());
var stoppedTask = factory.TransitionTo(State.Stopped, cancellationTokenSource.Token);
startedTask.Wait(TimeSpan.FromSeconds(3));
try
{
stoppedTask.Wait(TimeSpan.FromSeconds(3));
Assert.True(false, "Failed to throw exception.");
}
catch (AggregateException ex)
{
Assert.Equal(1, ex.InnerExceptions.Count);
Assert.IsType<OperationCanceledException>(ex.InnerExceptions[0]);
}
}
[Fact]
public void transition_to_can_be_forbidden()
{
var factory = new StateMachineTaskFactory<State>();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.FromResult(true));
var startedTask = factory.TransitionTo(State.Started, CancellationToken.None, x => x == State.Undefined);
var stoppedTask = factory.TransitionTo(State.Stopped, CancellationToken.None, x => x != State.Started);
startedTask.Wait(TimeSpan.FromSeconds(3));
try
{
stoppedTask.Wait(TimeSpan.FromSeconds(3));
Assert.True(false, "Failed to throw exception.");
}
catch (AggregateException ex)
{
Assert.Equal(1, ex.InnerExceptions.Count);
var ex2 = Assert.IsType<StateTransitionForbiddenException<State>>(ex.InnerExceptions[0]);
Assert.Equal(State.Stopped, ex2.TargetState);
Assert.Equal(State.Started, ex2.State);
Assert.Equal("A transition to state 'Stopped' was forbidden by the validate transition callback.", ex2.Message);
}
}
[Fact]
public void canceled_transition_reverts_back_to_original_state()
{
var factory = new StateMachineTaskFactory<State>();
var cancellationTokenSource = new CancellationTokenSource();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.Delay(TimeSpan.FromSeconds(3), cancellationTokenSource.Token));
factory.StateChanged += (s, e) =>
{
if (e.NewState == State.Stopping)
{
// cancel the stop
cancellationTokenSource.Cancel();
}
};
var startedTask = factory.TransitionTo(State.Started);
var stoppedTask = factory.TransitionTo(State.Stopped, cancellationTokenSource.Token);
startedTask.Wait(TimeSpan.FromSeconds(3));
try
{
stoppedTask.Wait(TimeSpan.FromSeconds(3));
Assert.True(false, "Failed to throw exception.");
}
catch (AggregateException ex)
{
Assert.Equal(1, ex.InnerExceptions.Count);
Assert.IsType<OperationCanceledException>(ex.InnerExceptions[0]);
Assert.Equal(State.Started, factory.State);
}
}
[Fact]
public void failed_transition_reverts_back_to_original_state()
{
var factory = new StateMachineTaskFactory<State>();
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => { throw new InvalidOperationException("Something went wrong"); });
var startedTask = factory.TransitionTo(State.Started);
var stoppedTask = factory.TransitionTo(State.Stopped);
startedTask.Wait(TimeSpan.FromSeconds(3));
try
{
stoppedTask.Wait(TimeSpan.FromSeconds(3));
Assert.True(false, "Failed to throw exception.");
}
catch (AggregateException ex)
{
Assert.Equal(1, ex.InnerExceptions.Count);
Assert.IsType<InvalidOperationException>(ex.InnerExceptions[0]);
Assert.Equal(State.Started, factory.State);
}
}
[Fact]
public void state_change_is_raised_as_state_changes()
{
var factory = new StateMachineTaskFactory<State>(State.Stopped);
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.FromResult(true));
var stateChanges = new List<StateChangedEventArgs<State>>();
factory.StateChanged += (s, e) => stateChanges.Add(e);
factory.TransitionTo(State.Started).Wait(TimeSpan.FromSeconds(1));
factory.TransitionTo(State.Stopped).Wait(TimeSpan.FromSeconds(1));
factory.TransitionTo(State.Started).Wait(TimeSpan.FromSeconds(1));
factory.TransitionTo(State.Stopped).Wait(TimeSpan.FromSeconds(1));
Assert.Equal(8, stateChanges.Count);
Assert.Equal(State.Stopped, stateChanges[0].OldState);
Assert.Equal(State.Starting, stateChanges[0].NewState);
Assert.Equal(State.Starting, stateChanges[1].OldState);
Assert.Equal(State.Started, stateChanges[1].NewState);
Assert.Equal(State.Started, stateChanges[2].OldState);
Assert.Equal(State.Stopping, stateChanges[2].NewState);
Assert.Equal(State.Stopping, stateChanges[3].OldState);
Assert.Equal(State.Stopped, stateChanges[3].NewState);
Assert.Equal(State.Stopped, stateChanges[4].OldState);
Assert.Equal(State.Starting, stateChanges[4].NewState);
Assert.Equal(State.Starting, stateChanges[5].OldState);
Assert.Equal(State.Started, stateChanges[5].NewState);
Assert.Equal(State.Started, stateChanges[6].OldState);
Assert.Equal(State.Stopping, stateChanges[6].NewState);
Assert.Equal(State.Stopping, stateChanges[7].OldState);
Assert.Equal(State.Stopped, stateChanges[7].NewState);
}
[Fact]
public void state_gets_the_current_state()
{
var factory = new StateMachineTaskFactory<State>(State.Stopped);
factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.Delay(TimeSpan.FromMilliseconds(100)));
factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.Delay(TimeSpan.FromMilliseconds(100)));
var task = factory.TransitionTo(State.Started);
Assert.Equal(State.Starting, factory.State);
task.Wait(TimeSpan.FromSeconds(3));
Assert.Equal(State.Started, factory.State);
task = factory.TransitionTo(State.Stopped);
Assert.Equal(State.Stopping, factory.State);
task.Wait(TimeSpan.FromSeconds(3));
Assert.Equal(State.Stopped, factory.State);
}
}
答案 2 :(得分:0)
可能不是你想要的,但是如果将它们排队而不是忽略是意图(或者是可接受的),那么一个相对简单的选择就是使用the limited-concurrency scheduler来进行这两个StartNew调用。
获取你正在寻找的效果所需的代码超过了必要的代码,但是可以让你利用已经编写的代码而不是编写自己的代码。 :)
答案 3 :(得分:-1)
好吧,如果你想一次只激活一个类的一个实例,你应该考虑使用单例模式。
我不是模式的专家,所以如果我使用的解决方案总是有一个名字,我不知道。我不使用任务而是使用线程。这是我的代码。
public class Service
{
private object oLock;
private bool running;
private Thread threadTask;
private AutoResetEvent taskStarted;
public bool IsRunning { get { return this.running; } }
public Service()
{
oLock = new object();
taskStarted = new AutoResetEvent(false);
running = false;
}
public void Start()
{
// If we can not acquire the lock, then there is a Start or Stop operation
// in progress, so better leave. Also leave if already running.
if (running || !Monitor.TryEnter(oLock))
return;
// Set running flag to prevent other threads to start service again
running = true;
// Create and start the thread
threadTask = new Thread(new ThreadStart(Task));
threadTask.IsBackground = true;
threadTask.Start();
// Wait until the task execution begins. This is optional
taskStarted.WaitOne();
// Release the lock
Monitor.PulseAll(oLock);
Monitor.Exit(oLock);
}
public void Stop()
{
// If we can not acquire the lock, then there is a Start or Stop operation
// in progress, so better leave. Also leave if not running.
if(!running || !Monitor.TryEnter(oLock))
return;
// Clear the running task to prevent reentrancy
running = false;
// Here we can abort the thread. This is optional an depends on task
threadTask.Abort();
// Wait until the thrad finish
threadTask.Join();
// Clear
threadTask = null;
// Release the lock
Monitor.PulseAll(oLock);
Monitor.Exit(oLock);
}
protected virtual void Task()
{
// Setup task and allocate resources
taskStarted.Set();
// Execute the task poll
while (running)
{
}
// Finish the task and release resources
}
}
其中一个技巧是使用Monitor类而不是lock语句,因此尝试启动服务的第一个线程将获胜,而其他线程将用于已经启动或停止的服务。如果您打算颠倒
的顺序,请小心if (Monitor.TryEnter() || running)
return;
你必须调用Monitor.Exit或你的应用程序将死锁。
当然,您可以更改枚举的运行布尔值,该枚举表示空闲,开始,运行和停止状态。
同样最好让类抽象化并让继承者覆盖在/而不是while语句中调用的方法。
希望这会有所帮助。 最好的问候。