如何在C#线程中使用等待句柄?

3
我的程序中有三个线程,当第一个线程完成后,我希望它能发信号通知第二个线程开始执行,而当第二个线程完成后,同样需要发信号通知第三个线程开始执行。请问如何实现这个功能?我知道在C#中可以使用wait handles来实现,但我不知道具体如何操作。以下是我的程序代码:
class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(Task1);
            Thread t2 = new Thread(Task2);
            Thread t3 = new Thread(Task3);

            t1.Start();
            t2.Start();
            t3.Start();

            Console.Read();
        }

        public static void Task1()
        {
            Console.WriteLine("I am assigned task 1:");
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine("Task1" );
            }
        }
        public static void Task2()
        {
            Console.WriteLine("I am assigned task 2:");
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine("Task2");
            }
        }
        public static void Task3()
        {
            Console.WriteLine("I am assigned task 3:");
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine("Task3");
            }
        }
    }

你可以将t2作为参数传递给t1.Start,然后在Task1结束时使用你得到的参数调用t2.Start()。为了使其正常工作,请使用ParameterizedThreadStart - Shadow The Spring Wizard
6个回答

6
你需要将事件传递给线程函数,以指示每个函数完成时要发出什么信号以及在运行之前要等待什么。看一下下面(未经测试的)代码,就会知道我在说什么:
class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(Task1);
            ManualResetEvent e1=new ManualResetEvent(false);

            Thread t2 = new Thread(Task2);
            ManualResetEvent e2=new ManualResetEvent(false);

            Thread t3 = new Thread(Task3);
            ManualResetEvent e3=new ManualResetEvent(false);

            t1.Start(()=>Task1(e1));
            t2.Start(()=>Task2(e1,e2));
            t3.Start(()=>Task3(e2,e3);

            Console.Read();

            t1.Join();
            t2.Join();
            t3.Join();
        }

        public static void Task1(EventWaitHandle handle)
        {
            Console.WriteLine("I am assigned task 1:");
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine("Task1" );
            }
            handle.Set();

        }
        public static void Task2(EventWaitHandle waitFor, EventWaitHandle handle)
        {
            waitFor.WaitOne();

            Console.WriteLine("I am assigned task 2:");
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine("Task2");
            }

            handle.Set();
        }
        public static void Task3(EventWaitHandle waitFor, EventWaitHandle handle)
        {
            waitFor.WaitOne();

            Console.WriteLine("I am assigned task 3:");
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine("Task3");
            }

            handle.Set();
        }
    }

你的等待句柄名称目前不正确。 - BrokenGlass
@BrokenGlass:没错。这样Task2和Task3将不会在一开始阻塞。Task1将设置Task2正在等待的句柄。然后,当Task2完成后,它将设置Task3正在等待的句柄。 - Sean
我不明白你的意思。它们在main()中声明,每个TaskXXX方法都有传递的句柄。你认为哪里缺少声明? - Sean

4

看起来你想要同步地运行任务1-3。因此,你可以这样做:

Task1();
Task2();
Task3();

如果你想把这些任务的执行转移到另一个线程,你可以这样做:
static void RunTasks()
{
    Task1();
    Task2();
    Task3();
}

static void Main()
{
   new Thread(RunTasks).Start();
}

如果你确实希望每个任务在单独的线程上运行,并等待前一个任务完成,可以使用Thread.Join方法。
编辑:
由于您真的想使用等待句柄来实现这一点,请查看ManualResetEvent类。
通知一个或多个等待的线程事件已发生。
调用 WaitOne 方法等待事件,调用 Set 方法信号它。
示例(可怕的编造代码):
var afterT1Event = new ManualResetEvent(false);
var afterT2Event = new ManualResetEvent(false);

Thread t1 = new Thread(() => { Task1(); afterT1Event.Set(); });
Thread t2 = new Thread(() => { afterT1Event.WaitOne(); Task2(); afterT2Event.Set(); });
Thread t3 = new Thread(() => { afterT2Event.WaitOne(); Task3(); });

t1.Start();
t2.Start();
t3.Start();

我的问题的目的是想要了解等待处理程序的工作原理,所以请给我一个例子... - Embedd_0913

2
如果你想使用WaitHandles来实现这个功能,你可以按照以下步骤操作:

声明以下两个字段:
static ManualResetEvent handle1 = new ManualResetEvent(false);
static ManualResetEvent handle2 = new ManualResetEvent(false);

在Task1的末尾添加以下内容:
    handle1.Set();

在Task2的开头添加:

    handle1.WaitOne();

最后,在末尾添加。
    handle2.Set();

然后,在Task3的开头添加:
    handle2.WaitOne();

0
你可以使用ManualResetEvents和WaitHandle.WaitAny。基本上,当一个线程完成时,你可以通过使用ManualResetEvent(ManualResetEvent.Set())来通知另一个线程。
ManualResetEvent threadFinished = new ManualResetEvent(false);

//You would set this in the thread that has finished
threadFinished.Set()

//You would use this in the thread that you want to wait for this event to be signalled
int nWait = WaitHandle.WaitAny(new ManualResetEvent[] { threadFinished }, 10, true);

//if yes stop thread
if (nWait == 0)
{
    //Thread is finished
}

0

我认为使用thread.join()会更简单,没有其他的解决方案。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接