1

私は 2 つのスレッド (プリンターとカウンター クラス) を持っています。では、最後に更新された数値を印刷した後にプリンター スレッドの実行を停止するにはどうすればよいでしょうか。最後の番号を 1 回または複数回表示することがあります。基本的に必要なのはプロパティを更新することであり、そのプロパティが更新されるたびに、更新された値をコンソールに出力する必要があり、プリンタースレッドは実行される更新の数を知りません。したがって、更新スレッドが更新を停止すると、停止する必要があります。

コードは次のようになります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Threads
{
    class Storage
    {
        static int _number;
        public readonly static object LockNumber = new object();
        public static int Number
        {
            get
            {
                lock(LockNumber)
                {
                    Monitor.Pulse(LockNumber);
                    return _number;
                }
            }
            set
            {
                lock(LockNumber)
                {
                    _number = value;
                    Monitor.Pulse(LockNumber);
                    Monitor.Wait(LockNumber);
                }
            }
        }
    }

    class Counter
    {

        public Thread t = new Thread(new ThreadStart(CounterFunction));

        public Counter()
        {
            t.Start();
        }
        public static void CounterFunction()
        {
            for (int i = 0; i < 25; i++)
            {
                Storage.Number = i;
            }
        }
    }

    class Printer
    {
        public Thread t1 = new Thread(new ThreadStart(Print));

        public Printer()
        {
            t1.Start();
        }
        public static void Print()
        {
            while (true)
            {
                Console.WriteLine("Number is " + Storage.Number);
            }
        }
    }

    class Check
    {
        static void Main()
        {
            Storage s1 = new Storage();
            Counter c = new Counter();
            Printer p = new Printer();

            c.t.Join();
            if (!c.t.IsAlive)
            {
                p.t1.Abort();
            }
            Thread.Sleep(10000);
        }
    }
}
4

3 に答える 3

0

これ以上更新がない場合は Storage.Number に数値 -1 を指定し、プリンターに if ステートメントを追加することで簡単に処理できます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Threads
{
    class Storage
    {
        static int _number;
        public readonly static object LockNumber = new object();
        public static int Number
        {
            get
            {
                lock (LockNumber)
                {
                    Monitor.Pulse(LockNumber);
                    return _number;
                }
            }
            set
            {
                lock (LockNumber)
                {
                    _number = value;
                    Monitor.Pulse(LockNumber);
                    Monitor.Wait(LockNumber);
                }
            }
        }
    }

    class Counter
    {

        public Thread t = new Thread(new ThreadStart(CounterFunction));

        public Counter()
        {
            t.Start();
        }
        public static void CounterFunction()
        {
            for (int i = 0; i < 25; i++)
            {
                Storage.Number = i;
            }
            Storage.Number = -1;
        }
    }

    class Printer
    {
        public Thread t1 = new Thread(new ThreadStart(Print));

        public Printer()
        {
            t1.Start();
        }
        public static void Print()
        {
            Boolean stop = false;
            while (!stop)
            {
                if (Storage.Number != -1)
                {
                    Console.WriteLine("Number is " + Storage.Number);
                }
                else
                {
                    stop = true;
                }
            }
        }
    }

    class Check
    {
        static void Main()
        {
            Storage s1 = new Storage();
            Counter c = new Counter();
            Printer p = new Printer();

            c.t.Join();
            if (!c.t.IsAlive)
            {
                p.t1.Abort();
            }
            Thread.Sleep(10000);
        }
    }
}

ただし、これでも一部の数値が 2 回出力されることになります。そのため、メイン クラス (Check) からスレッドを開始し、イベント ハンドラーを使用してスレッドを停止します。また、最後の値を Printer に保存して、値が 2 回印刷されないようにします (印刷はインクリメントよりもはるかに高速です)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace Threads
{
    class Storage
    {
        static int _number;
        public readonly static object LockNumber = new object();
        public static int Number
        {
            get
            {
                lock (LockNumber)
                {
                    Monitor.Pulse(LockNumber);
                    return _number;
                }
            }
            set
            {
                lock (LockNumber)
                {
                    _number = value;
                    Monitor.Pulse(LockNumber);
                    Monitor.Wait(LockNumber);
                }
            }
        }
    }

    class Counter
    {
        public delegate void Done();
        public event Done OnDone;

        public Counter()
        {
            //t.Start();
        }
        public void CounterFunction()
        {
            for (int i = 0; i < 25; i++)
            {
                Storage.Number = i;
            }
            Storage.Number = -1;
            if (OnDone != null)
            {
                OnDone();
            }
        }
    }

    class Printer
    {
        public Printer()
        {
            //t1.Start();
        }
        public void Print()
        {
            Boolean stop = false;
            int prevNumber = -1;
            while (!stop)
            {
                if (Storage.Number != -1)
                {
                    if (Storage.Number != prevNumber)
                    {
                        prevNumber = Storage.Number;
                        Console.WriteLine("Number is " + Storage.Number);
                    }
                }
                else
                {
                    stop = true;
                }
            }
        }
    }

    public partial class Check : Form //Invoking is a System.Windows.Forms function
    {
        public Thread _cThread;
        public Thread _pThread;

        static void Main()
        {
            Check ch = new Check();
        }

        public Check()
        {
            Storage s1 = new Storage();
            Counter c = new Counter();
            c.OnDone += new Counter.Done(countDone);
            Printer p = new Printer();

            _cThread = new Thread(new ThreadStart(c.CounterFunction));
            _pThread = new Thread(new ThreadStart(p.Print));
            _cThread.Start();
            _pThread.Start();
            while (true) ; //This is only here so that you can see the results.
        }

        private void countDone()
        {
            if (_pThread.IsAlive)
            {
                _pThread.Abort();
            }
            //Close the threads nicely
            if (this.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(this.countDone)); //This says: invoke and then call countDone.
            }
        }
    }
}

System.Windows.Forms を参照する必要があります

于 2013-11-26T14:23:25.797 に答える
0

AutoResetEventPrinter クラスにメンバーを追加します。プリンタースレッドで、そのWaitOne上で。これはビジーウェイトなしでブロックします。監視しているプロパティが更新されたら、Printer クラスによって処理されるイベントを発生させます。ハンドラーでSetは、AutoResetEvent. これにより、プリンター スレッドのブロックが解除されます。

このようなもの:

class Storage
{
    internal event Action<bool> NumberUpdated;
    {
        set
        {
            lock(LockNumber)
            {
                _number = value;
                if( NumberUpdated != null )
                   NumberUpdated( isLastUpdate ); //TODO: Add logic to compute it
                Monitor.Pulse(LockNumber);
                Monitor.Wait(LockNumber);
            }
        }
    }
}

class Printer
{
    private AutoResetEvent propertyUpdated;
    private bool keepPrinting;

    //Other code omitted for brevity's sake
    public Printer( Storage storage )
    {
        propertyUpdated = new AutoResetEvent();
        storage.NumberUpdated += OnStorageNumberUpdated;
        keepPrinting = true;
        t1.Start();
    }

    private void OnStorageNumberUpdated( bool isLastUpdate ){
       keepPrinting = !isLastUpdate;
       propertyUpdated.Set();
    }

    public static void Print()
    {
        while (keepPrinting)
        {
            propertyUpdated.WaitOne();
            Console.WriteLine("Number is " + Storage.Number);
        }
    }
}
于 2013-11-26T12:57:55.990 に答える