我有10个线程运行,我想控制信号,这样我就可以知道什么时候有5个线程向我发出信号,并能够阻止他们按需发送信号。
这是代码:
class A
{
static readonly Random r = new Random(DateTime.Now.Ticks.GetHashCode());
static int ID = 1;
int id;
public A() { id = ID++; }
public void SomeFunc(object o)
{
Thread.Sleep(r.Next(2000, 5000));
lock (o)
{
Console.WriteLine("A-{0} called Set!", id);
((EventWaitHandle)o).Set();
}
}
static void Main(string[] args)
{
AutoResetEvent are = new AutoResetEvent(false);
A[] arr = new A[10];
for (int i = 0; i < arr.Length; i++)
arr[i] = new A();
for (int i = 0; i < arr.Length; i++)
new Thread(arr[i].SomeFunc).Start(are);
int timesSetIsCalled = 0;
while (timesSetIsCalled < 5)
{
are.WaitOne();
timesSetIsCalled++;
}
Console.WriteLine("{0} threads called set", timesSetIsCalled);
Thread.Sleep(7000);
Console.WriteLine("{0} threads called set", timesSetIsCalled);
}
}考虑到N个线程已经调用了Set函数,我的问题是:
。
while (timesSetIsCalled < 5)
{
are.WaitOne();
timesSetIsCalled++;
}发布于 2015-12-11 01:24:08
只有调用Set()的线程才能计数调用Set()的线程。您无法从设置事件对象的线程外部观察到有多少线程设置了事件。
正如所发生的那样,解决这个问题需要将计数行为移到线程中,这样做也解决了您在退出while循环之后仍会继续进行计数的次要问题。
下面是您的代码的一个版本,它展示了您如何做到这一点:
class Program
{
static void Main(string[] args)
{
Random r = new Random();
WaitCounter counter = new WaitCounter();
A[] arr = new A[10];
for (int i = 0; i < arr.Length; i++)
arr[i] = new A(r.Next(2000, 5000), counter);
for (int i = 0; i < arr.Length; i++)
new Thread(arr[i].SomeFunc).Start();
while (counter.Counter < 5)
{
counter.Wait();
}
Console.WriteLine("{0} threads called set", counter.Counter);
Thread.Sleep(7000);
Console.WriteLine("{0} threads called set", counter.Counter);
}
}
class A
{
private static int ID = 1;
private static readonly Stopwatch sw = Stopwatch.StartNew();
private readonly int id;
private readonly int duration;
private readonly WaitCounter counter;
public A(int duration, WaitCounter counter)
{
id = ID++;
this.duration = duration;
this.counter = counter;
}
public void SomeFunc(object o)
{
Thread.Sleep(duration);
counter.Increment();
Console.WriteLine(
@"{0}-{1} incremented counter! Elapsed time: {2:mm\:ss\.fff}",
GetType().Name, id, sw.Elapsed);
}
}
class WaitCounter
{
private readonly AutoResetEvent _event = new AutoResetEvent(false);
private int _counter;
public int Counter { get { return _counter; } }
public void Increment()
{
Interlocked.Increment(ref _counter);
_event.Set();
}
public void Wait()
{
_event.WaitOne();
}
}备注:
Counter类。它抽象了跟踪线程进程所需的计数器,以及用于同步线程的AutoResetEvent。Interlocked用于增量;该事件被简单地设置为向主线程发出至少一个计数器的更改。这样,无论增加多少次或多少计数器,主线程总是能够准确地知道发生了多少次。Random实例移出线程方法本身,而在A类的所有实例之间共享它。这比以前要好,但仍然不完全正确:Random类不是线程安全的,而是依赖于内部状态来产生正确的结果。同时使用它会导致非随机的,或者至少是不正确的随机输出.我在这里通过让主线程创建和使用唯一的Random对象来解决这个问题,在线程对象真正开始运行之前,根据需要将值传递给它们。DateTime.Now.Ticks.GetHashCode()作为Random实例的种子。Random类已经默认使用基于系统时钟的种子。如果您的第二个问题是按照上述内容处理的,这是否仍然是必需的?看来可能不是。
但如果是的话,请张贴一个新的问题,明确你的意思。线程之间可以通过多种不同的方式进行通信,从您的问题中可以看出,您是否真的想阻止其他线程调用Set(),或者您是否只想延迟它们,在任何一种情况下,什么样的特定条件才能控制这种情况的发生。
https://stackoverflow.com/questions/34203822
复制相似问题