我对线程和异步处理缺乏经验,所以我不确定我所做的事情是否安全。
更新:不幸的是,这仅限于.Net 3.5所以没有ConcurrentQueue(除非有人为.Net 3.5实现了它或者知道替代实现?)
更新2:我发现this方法使用来自ConcurrentQueue的Mono实现的源(这是.Net 3.5的完全兼容的代码)。
我有一个对象是在内部管理Queue<MyObject>
的工作。此类需要异步执行其操作(它将在Windows服务的OnStart和OnStop事件之间连续运行)。无论如何,我会让代码进行讨论:
public class MyObjectQueueManager : IMyObjectQueueManager
{
private bool shouldContinueEnqueuing;
private readonly Queue<MyObject> queue;
private readonly IMyObjectIdentifier myObjectIdentifier;
public MyObjectQueueManager( IMyObjectIdentifier myObjectIdentifier )
{
this.myObjectIdentifier = myObjectIdentifier;
queue = new Queue<MyObject>();
}
public void StartQueue()
{
shouldContinueEnqueuing = true;
var enqueuer = new MyObjectEnqueuer( EnqueueMyObjects );
enqueuer.BeginInvoke( myObjectIdentifier, queue, StopEnqueuingMyObjects, new object() );
var dequeuer = new MyObjectDequeuer( DequeueMyObjects );
dequeuer.BeginInvoke( queue, StopDequeuingMyObjects, new object() );
}
public void StopQueue()
{
shouldContinueEnqueuing = false;
}
public event EventHandler<NextMyObjectEventArgs> OnNextMyObjectAvailable;
private void EnqueueMyObjects( IMyObjectIdentifier identifier, Queue<MyObject> queue )
{
while ( shouldContinueEnqueuing )
{
var myObjects = identifier.GetMyObjects();
foreach ( var myObject in myObjects )
{
queue.Enqueue( myObject );
}
WaitForQueueToShrink( queue, 1000 /* arbitrary queue limiter - will come from settings. */ );
}
}
private void DequeueMyObjects( Queue<MyObject> queue )
{
while ( queue.Count > 0 || shouldContinueEnqueuing )
{
if ( queue.Count > 0 )
{
OnNextMyObjectAvailable( this, new NextMyObjectEventArgs( queue.Dequeue() ) );
}
Thread.Sleep( 1 );
}
}
private static void WaitForQueueToShrink( ICollection queue, int queueLimit )
{
while ( queue.Count > queueLimit )
{
Thread.Sleep( 10 );
}
}
private static void StopEnqueuingMyObjects( IAsyncResult result )
{
var asyncResult = ( AsyncResult ) result;
var x = ( MyObjectEnqueuer ) asyncResult.AsyncDelegate;
x.EndInvoke( asyncResult );
}
private static void StopDequeuingMyObjects( IAsyncResult result )
{
var asyncResult = ( AsyncResult ) result;
var x = ( MyObjectDequeuer ) asyncResult.AsyncDelegate;
x.EndInvoke( asyncResult );
}
private delegate void MyObjectEnqueuer( IMyObjectIdentifier myObjectIdentifier, Queue<MyObject> queue );
private delegate void MyObjectDequeuer( Queue<MyObject> queue );
}
我的笔记/想法/关注:
作为奖励,我注意到有类似的代码用于从StopEnqueuingMyObjects和StopDequeuingMyObjects方法调用EndInvoke - 如果可以,我想重构使用单个方法但是当我尝试使用泛型方法时像这样:
private static void StopProcessingMyObjects<T>( IAsyncResult result )
{
var asyncResult = ( AsyncResult ) result;
var x = ( T ) asyncResult.AsyncDelegate;
x.EndInvoke( asyncResult );
}
它不喜欢这样,因为它不知道T
是一个delgate,因此无法调用EndInvoke
。有可能这样做吗?