簡體   English   中英

停止讀取MSMQ的服務

[英]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();
        }
    }
}

更新:我更改了AutoResetEventManualResetEvent的使用,以支持停止多個等待線程(使用ManualResetEvent ,一旦發出信號,所有等待線程將被通知並可以自由地繼續他們的工作 - 停止匯集消息,在您的情況下)。

使用揮發性bool並不能提供所有保證。 它仍然可以讀取過時的數據。 最好使用底層操作系統同步機制,因為它提供了更強大的保證。 資料來源: stackoverflow.com/a/11953661/952310

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM