[英]Stopping a service that reads MSMQ
我是一名Java程序員,他被要求對C#應用程序進行一些更改。 我已經和C#一起工作了一個星期了,而且我終於找到了一個觀察文檔沒有幫助的地方,當我谷歌時我找不到解決方案。
在這種情況下,我有一個Windows服務來處理到達MSMQ的消息。 當收到一條消息時,當前正在偵聽的線程將其拾取並開始執行需要幾秒鍾的操作。
public void Start()
{
this.listen = true;
for (int i = 0; i < Constants.ThreadMaxCount; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartListening), i);
}
...
private void StartListening(Object threadContext)
{
int threadId = (int)threadContext;
threads[threadId] = Thread.CurrentThread;
PostRequest postReq;
while(this.listen)
{
System.Threading.Monitor.Enter(locker);
try
{
postReq = GettingAMessage();
}
finally
{
System.Threading.Monitor.Exit(locker);
}
}
...
}
GettingAMessage()具有以下監聽消息的行:
Task<Message> ts = Task.Factory.FromAsync<Message>
(queue.BeginReceive(), queue.EndReceive);
ts.Wait();
問題是,當調用Stop()方法並且沒有消息進入MSMQ時,線程都坐在那里等待消息。 我嘗試過使用超時,但這種方法對我來說似乎並不優雅(並且切換到了Task Factory,我不知道如何實現它們)。 我的解決方案是將每個線程的引用添加到數組中,以便我可以取消它們。 創建后,每個工作線程調用以下內容。
threads[threadId] = Thread.CurrentThread;
然后應該被中止
public void Stop()
{
try
{
this.listen = false;
foreach(Thread a in threads) {
a.Abort();
}
}
catch
{...}
}
關於為什么不關閉線程的任何建議? (甚至更好,誰能告訴我應該在哪里找到如何正確取消ts.Wait()?)
使用ManualResetEvent
類可以正常和正常地停止正在運行的線程。
另外,不要將ThreadPool
用於長時間運行的線程,使用自己創建的線程,否則,對於許多長時間運行的任務,最終可能導致線程池飢餓,甚至可能導致死鎖:
public class MsmqListener
{
privatec ManualResetEvent _stopRequested = new ManualResetEvent(false);
private List<Thread> _listenerThreads;
private object _locker = new _locker();
//-----------------------------------------------------------------------------------------------------
public MsmqListener
{
CreateListenerThreads();
}
//-----------------------------------------------------------------------------------------------------
public void Start()
{
StartListenerThreads();
}
//-----------------------------------------------------------------------------------------------------
public void Stop()
{
try
{
_stopRequested.Set();
foreach(Thread thread in _listenerThreads)
{
thread.Join(); // Wait for all threads to complete gracefully
}
}
catch( Exception ex)
{...}
}
//-----------------------------------------------------------------------------------------------------
private void StartListening()
{
while( !_stopRequested.WaitOne(0) ) // Blocks the current thread for 0 ms until the current WaitHandle receives a signal
{
lock( _locker )
{
postReq = GettingAMessage();
}
...
}
//-----------------------------------------------------------------------------------------------------
private void CreateListenerThreads()
{
_listenerThreads = new List<Thread>();
for (int i = 0; i < Constants.ThreadMaxCount; i++)
{
listenerThread = new Thread(StartListening);
listenerThreads.Add(listenerThread);
}
}
//-----------------------------------------------------------------------------------------------------
private void StartListenerThreads()
{
foreach(var thread in _listenerThreads)
{
thread.Start();
}
}
}
更新:我更改了AutoResetEvent
與ManualResetEvent
的使用,以支持停止多個等待線程(使用ManualResetEvent
,一旦發出信號,所有等待線程將被通知並可以自由地繼續他們的工作 - 停止匯集消息,在您的情況下)。
使用揮發性bool
並不能提供所有保證。 它仍然可以讀取過時的數據。 最好使用底層操作系統同步機制,因為它提供了更強大的保證。 資料來源: stackoverflow.com/a/11953661/952310
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.