C#中的线程同步

时间:2013-11-26 12:47:45

标签: c# multithreading synchronization monitors

我有2个线程(在打印机和计数器类中)。计数器类更新存储中的属性,打印机打印它。现在我只想通过计数器打印更新的值一次。那么如何在打印完最后更新的号码后停止执行我的打印机线程。它有时打印一次或有时不止一次打印最后一个数字。基本上我需要的是更新属性,每次更新属性时,我需要在控制台上打印更新的值,并且打印机线程不知道将要发生的更新。所以它应该在更新线程停止更新时停止。

代码是这样的:

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

3 个答案:

答案 0 :(得分:1)

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%的处理器。没有真正的应用程序应该这样做。

答案 1 :(得分:0)

在Printer类中,添加AutoResetEvent成员。在打印机线程上,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);
        }
    }
}

答案 2 :(得分:0)

当没有更新更新并在打印机上添加if语句时,可以通过给予Storage.Number数字-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;
            }
            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)启动线程并使用事件处理程序来停止线程。 此外,我们将保存打印机中的最后一个值,以便不会打印任何值两次(打印速度大大提高,然后递增)。

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