如何使用一个线程执行多个定时操作而不是多个定时器

时间:2013-06-12 01:39:18

标签: c# wpf timer thread-sleep

忽视我的项目是创建一个交互式教程。我正在播放声音片段,在声音片段的某些时候我想要进行某些操作(例如,突出显示一个按钮)。我想出了一个解决方案,但我觉得它占用了大量的CPU。我想出的解决方案是为声音剪辑期间发生的每个动作设置每个单独的计时器。我预见如果我开始为50个不同的动作说出50个不同的定时器,那么最终会对CPU产生压缩,这会产生50个不同的线程。

以下是使用这些计时器的当前代码片段;

private void Label_FindingPart_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        sound.Source = new Uri(@"C:\SomeSound.wav");
        sound.Position = TimeSpan.Zero;  
        sound.Play();

        Timer_Logistics_Button(1000);
        Timer_Logistics_Window(1500);
        Timer_MMBE_Button(2000);
        Timer_MMBE_Window(2500);
    }
    //Timer initalized
    private void Timer_Logistics_Button(int interval_length)
    {
        System.Timers.Timer aTimer = new System.Timers.Timer();
        aTimer.AutoReset = false;
        aTimer.Elapsed += new ElapsedEventHandler(On_Timer_Logistics_Button);
        aTimer.Interval = interval_length;
        aTimer.Enabled = true;
    }
    //Action when the Elapsed event is raised.
    private void On_Timer_Logistics_Button(object source, ElapsedEventArgs e)
    {
        Dispatcher.BeginInvoke((Action)delegate()
        {
            Button_Logistics.Visibility = Visibility.Visible;
        });

    }
    //Timer initalized
    private void Timer_Logistics_Window(int interval_length)
    {
        System.Timers.Timer aTimer = new System.Timers.Timer();
        aTimer.AutoReset = false;
        aTimer.Elapsed += new ElapsedEventHandler(On_Timer_Logistics_Window);
        aTimer.Interval = interval_length;
        aTimer.Enabled = true;
    }
    //Action when the Elapsed event is raised.
    private void On_Timer_Logistics_Window(object source, ElapsedEventArgs e)
    {
        Dispatcher.BeginInvoke((Action)delegate()
        {
            Image_SAP_Main.Visibility = Visibility.Hidden;
            Image_SAP_Main_Logistics.Visibility = Visibility.Visible;
            Button_Logistics.Visibility = Visibility.Hidden;

        });

    }
    //Timer initalized
    private void Timer_MMBE_Button(int interval_length)
    {
        System.Timers.Timer bTimer = new System.Timers.Timer();
        bTimer.AutoReset = false;
        bTimer.Elapsed += new ElapsedEventHandler(On_Timer_MMBE_Button);
        bTimer.Interval = interval_length;
        bTimer.Enabled = true;
    }
    //Action when the Elapsed event is raised.
    private void On_Timer_MMBE_Button(object source, ElapsedEventArgs e)
    {
        Dispatcher.BeginInvoke((Action)delegate()
        {
            Button_MMBE.Visibility = Visibility.Visible;
        });
    }
    //Timer initalized
    private void Timer_MMBE_Window(int interval_length)
    {
        System.Timers.Timer bTimer = new System.Timers.Timer();
        bTimer.AutoReset = false;
        bTimer.Elapsed += new ElapsedEventHandler(On_Timer_MMBE_Window);
        bTimer.Interval = interval_length;
        bTimer.Enabled = true;
    }
    //Action when the Elapsed event is raised.
    private void On_Timer_MMBE_Window(object source, ElapsedEventArgs e)
    {
        Dispatcher.BeginInvoke((Action)delegate()
        {
            Image_SAP_Main_Logistics.Visibility = Visibility.Hidden;
            Button_MMBE.Visibility = Visibility.Hidden;
            Image_SAP_MMBE.Visibility = Visibility.Visible;
        });
    }

我的另一个想法是创建一个线程并让它与sound.play()同时启动。这一个线程将有多个thread.sleep()语句用于每个操作之间的等待时间。所以回想起来它会是这样的:

    Step A: Play();
    Step B: Thread.Start();
    Step C: Thread.sleep(1000);
    Step D: ACTION;
    Step E: Thread.sleep(500);
    Step F: ACTION;
    Step G: Thread.sleep(1200);
    Step H: ACTION;
    Step I: Thread.Stop();

下面的代码就我所能获得的线程而言,我很难从步骤D进入步骤E.我还需要找出如何正确地停止我的线程。下面的代码就是我能够解决的问题:

     System.Threading.Thread Tutorial_Thread = new System.Threading.Thread(new System.Threading.ThreadStart(
        delegate()
        {
            // Do the work here.
            Thread.Sleep(5000);


            this.Dispatcher.BeginInvoke(new Action(
            delegate()
            {
                // Invoke any updates to the GUI here.
                Button_Logistics.Visibility = Visibility.Visible;

            }
         ));
        }
         ));
        sound.Play();
        Tutorial_Thread.Start();

一旦线程通过,它将返回到线程的开头并执行该thread.sleep(5000)。我不知道如何通过线程改变每次旋转的睡眠时间和动作。任何帮助将不胜感激,我希望我提出问题清晰易懂。 我正在使用Visual Studio 2012,C#,WPF。

3 个答案:

答案 0 :(得分:0)

线程执行代码然后退出,除非你的代码循环,否则它不会循环。在您发布的示例中,线程等待5秒钟,更改按钮的可见性,然后退出。

所以...因为你有一个已定义的动作序列,你可以这样写:

Thread Tutorial_Thread = new Thread(() => 
    {
        Thread.Sleep(1000);
        this.Dispatcher.BeginInvoke(() => do_step_d());
        Thread.Sleep(500);
        this.Dispatcher.BeginInvoke(() => do_step_f());
        Thread.Sleep(1200);
        this.Dispatcher.BeginInvoke(() => do_step_h());
    });
Tutorial_Thread.Start();

线程将继续执行语句,暂停Sleep次调用,执行各种步骤方法,然后退出。

这当然是一个简单的例子。不是编写只执行单个序列的静态代码片段,而是为每个不同的序列编写类似的代码,您最好找出一个可以将事件序列排入...的调度系统...可能使用 mike z 建议处理时间安排。

答案 1 :(得分:0)

可以通过使用线程和Thread.Sleep来解决按顺序旋转多个事物以及某些部分之间的延迟,但是它可能会有问题,因为它引入了一个明确的等待,更不用说它在该持续时间内将该线程联系起来等待。

Microsoft引入了Task系统作为直接线程访问的事实上的高级替代。

一个例子是:

Play();
Task.Factory.StartNew(async () =>
    {
        await Task.Delay(1000);
        action_1();
        await Task.Delay(500);
        action_2();
        await Task.Delay(1200);
        action_3();
    });

// Task start returns immediately
Console.ReadLine();

这种方法比Thread.Sleep有许多优点,任务被安排,线程管理由你负责,任务也有组合函数(ContinueWith等),请参阅文档了解更多信息。

最大的优点是通过使任务本身成为异步方法(使用新的C#async / await),每次等待延迟时,底层线程都可以用于其他工作,所以你'不要让线程系统挨饿。

答案 2 :(得分:0)

我认为最简单的方法是使用async

private async void Label_FindingPart_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    sound.Source = new Uri(@"C:\SomeSound.wav");
    sound.Position = TimeSpan.Zero;  
    sound.Play();

    await Task.Delay(1000);
    Button_Logistics.Visibility = Visibility.Visible;

    await Task.Delay(500);
    Image_SAP_Main.Visibility = Visibility.Hidden;
    Image_SAP_Main_Logistics.Visibility = Visibility.Visible;
    Button_Logistics.Visibility = Visibility.Hidden;

    await Task.Delay(500);
    Button_MMBE.Visibility = Visibility.Visible;

    await Task.Delay(500);
    Image_SAP_Main_Logistics.Visibility = Visibility.Hidden;
    Button_MMBE.Visibility = Visibility.Hidden;
    Image_SAP_MMBE.Visibility = Visibility.Visible;
}

如果您需要停止,只需使用CancellationTokenSource并将其CancellationToken传递给所有Task.Delay来电。