我有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);
}
}
}
答案 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