7

私は C# アプリケーションに変更を加えるよう依頼された Java プログラマーです。私は C# を使って 1 週間が経ちましたが、ついにドキュメントを見ても解決策が見つからず、Google で検索しても解決策が見つからないところまで来ました。

この場合、MSMQ に到着するメッセージを処理する Windows サービスがあります。メッセージが受信されると、現在リッスンしているスレッドがそれを取得し、数秒かかる操作を実行するためにオフになります。

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 にメッセージが送信されない場合、すべてのスレッドがそこで待機してメッセージを待機することです。タイムアウトを使用してみましたが、その方法は私にはエレガントではないようです (そして、タスク ファクトリに切り替えたので、現在それらを実装する方法がわかりません)。これに対する私の解決策は、各スレッドの参照を配列に追加して、それらをキャンセルできるようにすることでした。以下は、作成後に各ワーカー スレッドによって呼び出されます。

threads[threadId] = Thread.CurrentThread;

そして、によって中止されることになっています

public void Stop()
{
    try
    {
        this.listen = false;
        foreach(Thread a in threads) {
            a.Abort();
        }
    }
    catch
    {...}
}

これがスレッドをシャットダウンしない理由について何かアドバイスはありますか? (または、さらに良いことに、ts.Wait() を適切にキャンセルする方法をどこで探すべきか誰か教えてもらえますか?)

4

1 に答える 1

5

クラスを使用して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();
        }
    }
}

更新:複数の待機中のスレッドの停止をサポートするためにAutoResetEventwith の使用を変更しました( を使用すると、シグナルを送信すると、待機中のすべてのスレッドに通知され、自由にジョブを続行できます。この場合、メッセージのプールを停止します)。ManualResetEventManualResetEvent

volatile を使用boolしても、すべての保証が得られるわけではありません。古いデータを読み取る可能性があります。はるかに強力な保証を提供するため、基盤となる OS 同期メカニズムを使用することをお勧めします。出典:stackoverflow.com/a/11953661/952310

于 2014-11-10T16:59:36.513 に答える