C#中的线程同步



我有两个线程(在打印机和计数器类中)。计数器类更新存储中的属性,打印机打印它。现在我只想按计数器打印一次更新的值。那么,在打印完最后一个更新的数字后,我该如何停止执行打印机线程呢。它有时打印最后一个数字一次,有时打印不止一次。基本上,我需要的是更新一个属性,每次更新该属性时,我都需要在控制台上打印更新后的值,而打印机线程不知道将要进行的更新数量。因此,当更新线程停止更新时,它应该停止。

代码如下:

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);
        }
    }
}
public static void Print()
{
    int prevNumber = Storage.Number;
    while (true)
    {
        int number = Storage.Number;
        if (number !=prevNumber) {   
            Console.WriteLine("Number is " + number);
            prevNumber = number;
        }
    }
}

这应该会有所帮助。尽管这是繁忙的等待,并将消耗100%的处理器。任何真正的应用程序都不应该这样做。

在Printer类中,添加一个AutoResetEvent成员。在打印机线程上,它上有WaitOne。这将在没有忙等待的情况下阻止。更新正在监视的属性时,引发由Printer类处理的事件。在处理程序中,SetAutoResetEvent。这将取消阻止打印机线程。

类似这样的东西:

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);
        }
    }
}

当没有更多更新时,通过给Storage编号-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);
        }
    }
}

尽管这仍然会导致一些数字被打印两次。因此,我们从主类(Check)启动线程,并使用事件处理程序来停止线程。此外,我们将把最后一个值保存在Printer中,这样就不会打印两次值(打印速度大多比递增快得多)。

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

相关内容

  • 没有找到相关文章

最新更新