WaitHandle背后的基本概念是什么?

Dot*_*ner 58 .net c# multithreading

WaitHandleC#.net线程背后的基本概念是什么?它的用途是什么?什么时候用?什么是利用了WaitAll了WaitAny里面的方法呢?

KMå*_*Mån 60

每当您想要控制应用程序中多个线程的执行时.虽然这不仅意味着只有一个线程增加计数器; 但让线程开始/停止或暂停一个事件.

请参阅WaitHandles - Auto/ManualResetEvent和Mutex

- 编辑 -

WaitHandles为的机制,你"使用"控制线程的执行.它不是关于在一个线程内无法访问的句柄; 它在线程中使用它们.

这可能是一个肥胖的例子,但请耐心等待; 想一想,一位女士给五个女孩提供了五种不同的口哨声,并告诉他们每当something发生时吹哨子; 这个过程是让每个女孩吹口哨,这位女士会知道是谁吹响了哨子.

现在,它不是为了分享彼此的口哨,它可能是为了女士,用它来"控制"女孩吹哨的执行或过程.

因此,从技术上讲,这个过程将是:

  1. 创建一个等待事件(ManualResetEvent对象)
  2. 注册活动, WaitHandle.WaitAny(events);
  3. 在你的线程中完成操作之后.Set(),会告诉WaitHandle"我完成了!".

例如,请考虑提供的链接中的示例.我已经添加了让您理解逻辑的步骤.这些不是硬编码的步骤,但您可能会理解.

class Test
{
    static void Main()
    {
    //STEP 1: Create a wait handle
        ManualResetEvent[] events = new ManualResetEvent[10];//Create a wait handle
        for (int i=0; i < events.Length; i++)
        {
            events[i] = new ManualResetEvent(false);
            Runner r = new Runner(events[i], i); 
            new Thread(new ThreadStart(r.Run)).Start();
        }

    //STEP 2: Register for the events to wait for
        int index = WaitHandle.WaitAny(events); //wait here for any event and print following line.

        Console.WriteLine ("***** The winner is {0} *****", 
                           index);

        WaitHandle.WaitAll(events); //Wait for all of the threads to finish, that is, to call their cooresponding `.Set()` method.

        Console.WriteLine ("All finished!");
    }
}


class Runner
{
    static readonly object rngLock = new object();
    static Random rng = new Random();

    ManualResetEvent ev;
    int id;

    internal Runner (ManualResetEvent ev, int id)
    {
        this.ev = ev;//Wait handle associated to each object, thread in this case.
        this.id = id;
    }

    internal void Run()
    {
    //STEP 3: Do some work
        for (int i=0; i < 10; i++)
        {
            int sleepTime;
            // Not sure about the thread safety of Random...
            lock (rngLock)
            {
                sleepTime = rng.Next(2000);
            }
            Thread.Sleep(sleepTime);
            Console.WriteLine ("Runner {0} at stage {1}",
                               id, i);
        }

    //STEP 4: Im done!
        ev.Set();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • ruffin:因为它必须是某种东西。袋鼠和小袋鼠也好不到哪里去,尤其是因为它们通常不吹口哨。 (2认同)

Ada*_*son 31

WaitHandle是两个常用事件句柄的抽象基类:AutoResetEventManualResetEvent.

这两个类都允许一个线程"发信号通知"一个或多个其他线程.它们用于在线程之间同步(或序列化活动).这是使用SetWaitOne(或WaitAll)方法完成的.例如:

线程1:

// do setup work

myWaitHandle.Set();
Run Code Online (Sandbox Code Playgroud)

线程2:

// do setup work

myWaitHandle.WaitOne();

// this code will not continue until after the call to `Set` 
// in thread 1 completes.
Run Code Online (Sandbox Code Playgroud)

这是一个非常基本的例子,网上有很多可用的例子.基本思想是WaitOne用于等待来自另一个线程的信号,该信号表明发生了某些事情.在AsyncWaitHandle(通过异步调用委托返回)的情况下,WaitOne允许您使当前线程等待异步操作完成.

当a AutoResetEvent或未ManualResetEvent设置时,调用WaitOne将阻止调用线程直到Set被调用.这两个类的不同之处仅在于,AutoResetEvent一旦成功调用WaitOne完成后"取消设置"事件,使后续调用再次阻塞直到Set被调用.ManualResetEvent必须通过调用显式"取消设置" Reset.

WaitAll并且WaitAnyWaitHandle类上的静态方法,允许您指定WaitHandles要等待的数组.WaitAll将阻塞,直到所有提供的句柄Set,但WaitAny只会阻止,直到其中一个获得Set.


Han*_*ant 9

它是一个抽象类,您不直接使用它.具体的派生类是ManualResetEvent,AutoResetEvent,Mutex和Semaphore.工具箱中用于实现线程同步的重要类.它们继承WaitOne,WaitAll和WaitAny方法,您可以使用它们来检测一个或多个线程发出等待条件的信号.

Manual/AutoResetEvent的典型使用场景是告诉线程退出或让线程发出信号表明它已经进展到一个重要的序列点.信号量可以帮助您限制执行操作的线程数.或者实现不应该与特定线程具有亲缘关系的线程同步.Mutex用于将一段代码的所有权分配给一个线程,锁定语句通常也适用于那里.

已经有关于它的书籍.Joe Duffy 在Windows中并发编程是最新最好的.强烈建议您考虑编写线程代码.


Joe*_*orn 7

想象一下,你有一个包含1000个项目的数组.您需要对每个项目进行一些处理.这项工作需要一些时间,但不受I/O限制.

例如,您可能需要使用每个项目来生成低带宽Web请求.您有足够的吞吐量来同时请求多个项目,并且每个Web请求中的延迟意味着一次执行一个可能需要比您想要的更长的时间.

进入并行编程的世界.今天,有许多方法可以处理这项任务,并且WaitHandle是其中的一个基本部分.即使你不使用WaitHandle直接,无论您选择的选项可能依靠WaitHandle诸如WaitAllWaitAny幕后.

继续这个例子,假设你有一个典型的四核CPU.在这种情况下,同时拥有4个以上的线程并没有多大意义.*所以4个线程,但1000个项目; 你是做什么?

一种选择使用WaitAny.你启动了4个线程,每次该WaitAny方法返回时你都会启动另一个,直到所有1000个项目都排队.请注意,这是一个很糟糕的例子WaitAny,因为我们知道总共有多少项,并且可以以相同的速率访问任何项目.WaitAny最好只有顺序访问权限.还有其他类似的情况WaitAny可以很有意义.

另一个选择使用WaitAll.您不是一次排队一个项目,而是为四个核心中的每个核心设置一个线程,为其分配不同的250个项目段.使用此选项,您可以使用WaitAll等待所有处理完成.


*实际上,确实如此.CPU通常会有一定的I/O时间,这样你就可以通过每个核心运行多个线程来做得更好.但这是另一个故事.