我有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函数 我的问题是:
如何阻止其他线程(已经运行)调用Set?
如何在主要的while循环之后继续计算调用Set的踏板?我必须算在锁定区域内?如果是这样,我怎样才能将一个ref变量发送给线程以便包含?
while (timesSetIsCalled < 5)
{
are.WaitOne();
timesSetIsCalled++;
}
答案 0 :(得分:1)
- 如何在主要的while循环之后继续计算调用Set的踏板?我必须算在锁定区域内?如果是这样,我怎样才能将一个ref变量发送到线程以便inc?
醇>
只有调用System.MissingMethodException was unhandled
Message: An unhandled exception of type 'System.MissingMethodException' occurred in NewSol1.exe
Additional information: Method not found: 'Microsoft.FSharp.Collections.FSharpList`1<System.String> MyLib.Extensions.Extension1.ext1Method1(System.String)'.
的线程才能计算调用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
类已默认使用基于系统时钟的种子。
- 如何阻止其他线程(已经运行)调用Set?
醇>
如果您的第二个问题按上述方式解决,是否还需要这个?似乎可能不是。
但如果是的话,请发一个新问题,明确你的意思。线程可以通过很多不同的方式相互通信,并且从您的问题中不清楚您是否确实希望阻止其他线程调用Random
或者你只想延迟它们,在任何一种情况下,特定的条件将控制是否发生这种情况。