我有两个线程(在打印机和计数器类中)。计数器类更新存储中的属性,打印机打印它。现在我只想按计数器打印一次更新的值。那么,在打印完最后一个更新的数字后,我该如何停止执行打印机线程呢。它有时打印最后一个数字一次,有时打印不止一次。基本上,我需要的是更新一个属性,每次更新该属性时,我都需要在控制台上打印更新后的值,而打印机线程不知道将要进行的更新数量。因此,当更新线程停止更新时,它应该停止。
代码如下:
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类处理的事件。在处理程序中,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);
}
}
}
当没有更多更新时,通过给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