【问题标题】:Thread Dispatcher Sleep in WPFWPF 中的线程调度程序休眠
【发布时间】:2011-12-18 05:34:02
【问题描述】:

我正在尝试创建 Kinect + WPF 应用程序。 Kinect 部分工作正常;现在我想创建一个方法来检查页面是否空闲(没有用户在特定时间内与程序交互)。如果闲置 5 秒,屏幕将被锁定。这是算法:

  1. 启动线程(我需要使用 Dispatcher,因为线程需要修改 WPF 元素)
  2. 检查用户是否正在使用。如果不是,则将 Count 增加 1。
  3. 如果 Count == 9(这意味着已经过了 5 秒),锁定屏幕并再次将 Count 设置为 0。
  4. 休眠 500 毫秒。
  5. 重复步骤 2-4

这是我的代码。应用程序启动时调用方法“startLockHandler”。

 public void startLockHandler()
 {
     Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() => lockHandler()), null);
 }

 public void lockHandler()
    {
        while (true)
        {
            if (myState.isSkeletonTracked == false) //if skeleton is no longer tracked 
            {
                if (myState.ActionAllowed == true) //if the page is not in transition
                {
                    lockCount++;

                    if (lockCount >= 10)
                    {
                        lockCount = 0;

                        myState.ActionAllowed = false;

                        //LOCKING MECHANISM INSERTED HERE. NEED TO MODIFY SOME WPF ELEMENTS
                        myState.ActionAllowed = true;
                    }
                }
            }

            else
            {
                lockCount = 0;
            }
            Console.WriteLine("lockHandler: THREAD SLEEP CALLED");
            Thread.Sleep ( 500 );

        }//end while
    }//end method lockHandler 

当我运行应用程序时,应用程序在启动后立即挂起。我认为发生的是 Thread.Sleep (500) 指示主线程进入睡眠状态(如果我错了,请纠正我)。我的问题是如何指定要让哪个线程进入睡眠状态? 顺便说一句,我不是 C# 方面的专家,也不是线程方面的新手 :(

感谢您的关注,希望您能帮助我:)

【问题讨论】:

  • 在生产代码中休眠通常是个坏主意(tm)
  • 我想不出任何其他解决方案..
  • 为什么不使用Timer 而不是Thread.Sleep

标签: c# wpf multithreading dispatcher


【解决方案1】:
  1. Dispatcher.BeginInvoke() 不创建新线程,它只是在主 GUI 线程上执行 lockHandler()。您传递ThreadStart 委托的事实在这里没有什么特别的意义。

  2. Thread.Sleep() 使调用它的线程进入睡眠状态,在您的情况下是主 GUI 线程。要控制一个线程与另一个线程的执行,您应该使用同步原语(ManualResetEventAutoResetEventMutexSemaphore 等)。

  3. 您不应该直接从另一个线程访问/修改 UI,您必须从辅助线程(不是 GUI 线程)调用 InvokeBeginInvoke Dispatcher 方法以确保执行所有与 UI 相关的代码来自创建 UI 元素的线程。

  4. 对于您的情况,您实际上并不需要具有专用 Dispatcher 实例的辅助线程。

最少的修改,至少会使用一个单独的线程:

var thread = new Thread(lockHandler);
thread.Start();

请记住,您还需要实现一种方法来停止辅助线程,否则它可能会阻止您的应用程序关闭并从内存中卸载。一个快速和(非常)肮脏的解决方案是将这个线程标记为后台线程:thread.IsBackground = true

更新

从辅助线程修改 UI 示例:

Application.Current.Dispatcher.BeginInvoke(new Action(
    () =>
    {
         // access UI elements here, for example
         myState.ActionAllowed = false;
    }));

【讨论】:

  • 如果我不使用 Dispatcher,则会出现错误“调用线程无法访问此对象,因为不同的线程拥有它。”将显示为线程无法修改 WPF 元素。你能给出你的答案 3 的代码示例吗?我很难理解。
  • 我没有说你不需要使用Dispatcher,你应该从另一个线程中使用它,它不是你创建的。已添加示例。
猜你喜欢
  • 2013-02-07
  • 1970-01-01
  • 1970-01-01
  • 2014-12-27
  • 1970-01-01
  • 2019-08-12
  • 1970-01-01
  • 2014-06-01
  • 2011-09-18
相关资源
最近更新 更多