首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

分享一个UI多任务拥塞处理的源代码

2013-02-28 
分享一个UI多任务阻塞处理的源代码问题在这里http://bbs.csdn.net/topics/390369970既要阻塞UI线程等待非U

分享一个UI多任务阻塞处理的源代码
问题在这里http://bbs.csdn.net/topics/390369970
既要阻塞UI线程等待非UI线程结束,又要在非UI线程中进行UI操作,简单的Wait肯定会造成死锁。
因为很多时候UI与非UI操作夹杂在一起,写程序很方便。
为了解决这个问题,所以我写了一个比较通用的基于fastCSharp处理类。
就是建立一个UI任务队列,UI线程Wait新任务,非UI线程Pulse唤醒UI线程。

using System;
using System.Threading;
using fastCSharp;
using fastCSharp.threading;

namespace showjim.console
{
    /// <summary>
    /// UI多任务阻塞处理
    /// </summary>
    public class uiWait
    {
        /// <summary>
        /// 任务信息
        /// </summary>
        private class taskInfo
        {
            /// <summary>
            /// 执行委托
            /// </summary>
            public action Action;
            /// <summary>
            /// 等待完成锁
            /// </summary>
            public object WaitLock;
            /// <summary>
            /// 任务是否已完成
            /// </summary>
            public bool isFinally;
            /// <summary>
            /// 等待任务完成
            /// </summary>
            public void Wait()
            {
                Monitor.Enter(WaitLock);
                try
                {
                    if (!isFinally) Monitor.Wait(WaitLock);
                }
                finally { Monitor.Exit(WaitLock); }
            }
            /// <summary>
            /// 执行任务
            /// </summary>
            public void Run()
            {


                if (Action != null)
                {
                    try
                    {
                        Action();
                    }
                    catch (Exception error)
                    {
                        fastCSharp.log.Default.Add(error, null, false);
                    }
                }
                if (WaitLock != null)
                {
                    isFinally = true;
                    Monitor.Enter(WaitLock);
                    try
                    {
                        Monitor.Pulse(WaitLock);
                    }
                    finally { Monitor.Exit(WaitLock); }
                }
            }
        }
        /// <summary>
        /// 非UI任务
        /// </summary>
        private readonly task task;
        /// <summary>
        /// UI任务集合
        /// </summary>
        private list<taskInfo> tasks = new list<taskInfo>();
        /// <summary>
        /// UI任务访问锁
        /// </summary>
        private readonly object taskLock = new object();


        /// <summary>
        /// 是否开始运行UI任务
        /// </summary>
        private bool isRun;
        /// <summary>
        /// 是否以线程的方式运行UI任务
        /// </summary>
        private bool isRunThread;
        /// <summary>
        /// 非UI任务是否已完成
        /// </summary>
        private bool isTaskFinally;
        /// <summary>
        /// UI任务是否已完成
        /// </summary>
        private bool isFinally;
        /// <summary>
        /// UI任务完成锁
        /// </summary>
        private readonly object finallyLock = new object();
        /// <summary>
        /// UI多任务阻塞处理
        /// </summary>
        /// <param name="task">非UI任务</param>
        public uiWait(task task)
        {
            if (task == null) fastCSharp.log.Default.Throw(log.exceptionType.Null);
            this.task = task;
        }
        /// <summary>
        /// 添加新的UI任务
        /// </summary>
        /// <param name="task">任务信息</param>
        private void add(taskInfo task)
        {
            Monitor.Enter(taskLock);
            try
            {
                tasks.Add(task);
                Monitor.Pulse(taskLock);
            }
            finally { Monitor.Exit(taskLock); }
        }
        /// <summary>
        /// 添加新的UI任务
        /// </summary>
        /// <param name="run">任务执行委托</param>


        public void Add(action run)
        {
            if (run != null) add(new taskInfo { Action = run });
        }
        /// <summary>
        /// 添加新的UI任务
        /// </summary>
        /// <typeparam name="parameterType">任务参数类型</typeparam>
        /// <param name="run">任务执行委托</param>
        /// <param name="parameter">任务参数</param>
        public void Add<parameterType>(action<parameterType> run, parameterType parameter)
        {
            if (run != null) add(new taskInfo { Action = run<parameterType>.Create(run, parameter) });
        }
        /// <summary>
        /// 添加新的UI任务并同步等待任务完成
        /// </summary>
        /// <param name="info">任务信息</param>
        private void addWait(taskInfo info)
        {
            add(info);
            info.Wait();
        }
        /// <summary>
        /// 添加新的UI任务并同步等待任务完成
        /// </summary>
        /// <param name="run">任务执行委托</param>
        public void AddWait(action run)
        {
            addWait(new taskInfo { Action = run, WaitLock = new object() });
        }
        /// <summary>
        /// 添加新的UI任务并同步等待任务完成
        /// </summary>
        /// <typeparam name="parameterType">任务参数类型</typeparam>
        /// <param name="run">任务执行委托</param>
        /// <param name="parameter">任务参数</param>
        public void AddWait<parameterType>(action<parameterType> run, parameterType parameter)
        {
            addWait(new taskInfo { Action = run<parameterType>.Create(run, parameter), WaitLock = new object() });
        }


        /// <summary>
        /// 检测是否开始运行UI任务
        /// </summary>
        private void checkRun()
        {
            Monitor.Enter(taskLock);
            try
            {
                if (isRun) fastCSharp.log.Default.ThrowReal(log.exceptionType.ErrorOperation);
                isRun = true;
            }
            finally { Monitor.Exit(taskLock); }
        }
        /// <summary>
        /// 等待非UI任务结束
        /// </summary>
        private void wait()
        {
            task.Dispose(true);
            isTaskFinally = true;
            Monitor.Enter(taskLock);
            try
            {
                Monitor.Pulse(taskLock);
            }
            finally { Monitor.Exit(taskLock); }
        }
        /// <summary>
        /// 执行UI任务
        /// </summary>
        private void run()
        {
            list<taskInfo> runTasks = new list<taskInfo>(), oldTasks;
            while (true)
            {
                Monitor.Enter(taskLock);
                try
                {
                    if (tasks.Count == 0)
                    {
                        if (isTaskFinally) break;
                        Monitor.Wait(taskLock);


                    }
                    oldTasks = runTasks;
                    runTasks = tasks;
                    tasks = oldTasks;
                }
                finally { Monitor.Exit(taskLock); }
                foreach (taskInfo task in runTasks) task.Run();
                runTasks.Empty();
            }
            isFinally = true;
            Monitor.Enter(finallyLock);
            try
            {
                Monitor.Pulse(finallyLock);
            }
            finally { Monitor.Exit(finallyLock); }
        }
        /// <summary>
        /// 异步执行UI任务
        /// </summary>
        public void RunThread()
        {
            checkRun();
            new thread(wait).Start();
            new thread(run).Start();
            isRunThread = true;
        }
        /// <summary>
        /// 等待异步执行UI任务结束
        /// </summary>
        public void WaitThread()
        {
            if (isRunThread)
            {
                Monitor.Enter(finallyLock);
                try
                {
                    if (!isFinally) Monitor.Wait(finallyLock);
                }
                finally { Monitor.Exit(finallyLock); }


            }
            else fastCSharp.log.Default.ThrowReal(log.exceptionType.ErrorOperation);
        }
        /// <summary>
        /// 执行UI任务并等待任务结束
        /// </summary>
        public void Wait()
        {
            checkRun();
            new thread(wait).Start();
            run();
        }
    }
}


支持同步与异步两种模式,uiWait是一个实例

[解决办法]
好东西,支持一下
[解决办法]
好东西,感谢分享
[解决办法]
感谢分享,帮你顶下。
[解决办法]
必须要顶分享一个UI多任务拥塞处理的源代码
[解决办法]
收藏下,以后可能有用
[解决办法]
收藏下,以后可能有用 
[解决办法]
非常有用,谢谢分享!
[解决办法]

if (run != null) add(new taskInfo { Action = run<parameterType>.Create(run, parameter) });

报错
[解决办法]
Mark,感谢分享!
[解决办法]
if (run != null) add(new taskInfo { Action = run<parameterType>.Create(run, parameter) });

报错!
[解决办法]
不知道用不用得到,先看看
------解决方案--------------------


先预备着,谢谢LZ
[解决办法]
分享一个UI多任务拥塞处理的源代码
[解决办法]
分享一个UI多任务拥塞处理的源代码
[解决办法]



[解决办法]
感谢分享分享一个UI多任务拥塞处理的源代码
[解决办法]
感谢分享,收藏了。。。。
[解决办法]
谢谢,学习了
[解决办法]
这个好,学习一下
[解决办法]
技术贴必须要顶
[解决办法]
不错啊,值得收藏
[解决办法]
谢谢搂住风向
[解决办法]
感谢分享,帮你推荐下。

[解决办法]
感谢分享,帮你推荐下
[解决办法]
分享一个UI多任务拥塞处理的源代码有空调时看看.
[解决办法]
   学习一下多线程知识。
[解决办法]
认真观摩先进经验
[解决办法]
感谢分享,帮你推荐下。 
[解决办法]
嗯,值得看,不错啊
[解决办法]
感谢分享,帮你顶下。
[解决办法]
分享一个UI多任务拥塞处理的源代码分享一个UI多任务拥塞处理的源代码谢谢
[解决办法]
分享一个UI多任务拥塞处理的源代码感谢...
[解决办法]
不知道好使不,先看看再说
[解决办法]
初学者。。。膜拜下~
[解决办法]
谢谢分享,拜读一下。
[解决办法]
谢谢分享,以后说不定能用到!
[解决办法]
先占楼 免得找不到了
[解决办法]
不知道好使不,先看看再说 
[解决办法]
看看再说......
[解决办法]
哇塞,不错。。。
[解决办法]
引用:

引用:
你有引用fastCSHarp吗?


VS2012 没有引用fastCSHarp ,我去找个试下分享一个UI多任务拥塞处理的源代码
[解决办法]
感谢分享,谢谢
[解决办法]
不论winform还是wpf,甚至web,UI都是单线程的,所以一边只要保证一个线程循环处理界面事件即可,还需要队列,如果有需要,可以设计几个优先级别不一样的队列,然后设计一个类,用来存放事件和参数,当有事件的时候,存入该队列,并增加一个信号量,循环线程则取队列,然后处理;

由于采用了多线程,界面处理的入口一半放置到主窗体下,并在主窗体使用异步方式调用,BeginInvoke和Invoke来执行,再根据需要,分发到各组件和各窗体进行处理;

具体思路都是这样,一个事件类,一个事件队列,一个线程循环,配合线程锁和信号亮,来实现多任务UI处理,封装好后,比较理想的状态是:一个事件添加入口,一个事件处理出口,一个事件抛弃接口,一个线程终止接口(退出程序事用);
[解决办法]
如果我没猜错,你这个方法必须对UI操作的部分进行封装,然后传递给uiWait进行并行处理。显然这个封装是最麻烦的,如果一个耗时的操作中频繁穿插UI操作,那么封装的数量将会非常多,如果整体封装,那么调用你的方法没任何效果,因为耗时操作转个弯又跑到了UI线程中去执行了,最终的表现仍旧是卡界面。我这里要强调的是,卡界面不是因为Wait信号造成的,更多的是代码本身和UI打交道的时间过长造成的,比如循环列表每行数据进行改动。
[解决办法]
DOTNET35符号添加了,是WPF回调方式和WinForm有显著不同,它是通过一个叫Dispatcher的管理器来统一管理线程的,你不能通过控件进行Invoke。
其实我只是要试验下你的代码能实现的效果,我也看了下微软的async/await关键字的处理,最终确定要实现完美的界面无阻塞,不是那么简单的,微软背后进行了偷梁换柱才实现了这样的效果,而你的代码就那么点内容,绝对不可能实现那种效果。
[解决办法]
有一种需求,你看能否实现,微软在.NET4.5里面实现了。
首先是一段正常执行的代码,因为耗时非常少,所以放在UI线程中直接执行,然后一段非常耗时的代码进来了,要不卡界面,只能用多线程执行,但是我需要在这个耗时代码结束的时候,继续执行UI操作,虽然可以通过委托回调的方式,在多线程结束的时候回调去处理,但是这样代码看起来就被分隔开了,不易读懂,编码量也增加了。微软在NET4.5里面是这样处理的,非常耗时的多线程操作作为UI线程的不部分,通过await关键字去等待该部分的执行结束,而这个等待可以做到不卡界面,只要执行的过程是异步的(同步的过程仍旧会卡界面的),如果不用await去等待,异步执行后面的代码会立刻执行,用了await去等待,后面的代码会等待这个异步过程结束后才去执行,并且等待中不卡界面。
使用async/await关键字后,整个多线程编程过程中,随意插进来的多线程部分等待和同步等待一样进行编码,代码看起来非常舒服。(编译后的IL偷梁换柱,很难读懂的)
[解决办法]
这难道是传说中的动态编译?我看到Compile关键字了。
你这样给代码比较难理解,最好有个使用部分的完整Demo,显然你只是在说明你的核心代码如何在工作,但我现在对你的代码如果调用还不清楚,自然要演示一个效果出来也难。我需要先看到它能做到什么,通过实际的代码来说明,然后才去看它如何实现的。
[解决办法]
能不能给一个最简单的应用。
一个窗口,里面一个按钮,按钮添加一个点击事件。
事件的开头先new另一个窗口出来,那个窗口里面只有一个进度条,开启自己滚动的效果。
在show这个窗口出来后,执行另一个耗时的方法,这个方法就一行代码Thread.Sleep(10000);
这个耗时方法结束后,关闭打开的窗口。

我需要的效果是,在这个10秒内,界面不会卡,不会卡的表现就是那个新建的窗口中的滚动条能够正常滚动。同时这个窗口必须等待10秒后关闭,而所有这些方法要写在按钮的点击事件中,只有那个耗时的方法(10秒等待)是封装的,为了开启多线程。
[解决办法]
补充:
前面说的是同步代码中插入异步等待的需求,下面还有一种需求是——异步代码中插入同步访问的。

如果我的代码异步操作量非常大,那代码本身就放在一个异步线程中去执行了,但是里面会有不少数据来源于界面的控件,虽然可以预先采集那些数据,但灵活性不好,因此最好是一边写代码,一边访问这些控件的属性,这时会提示非UI线程不能访问,就需要委托回调来读取属性值。我的想法是,编写一个能够在异步线程中支持同步访问控件属性或方法的通用类即可,从楼主你给的类中,似乎没提供这样的功能。
[解决办法]
看来离我预期的差太远了,在.NET中,开启多线程其实很容易的,而且方法也有很多种,仅仅要实现多线程的话,完全没必要封装调用这个uiWait,我自己创建委托,自己调用还好控制些,只有能达到我上述要求的才有封装的意义。
[解决办法]
看来你没理解我的意思,我所谓能看到进度条滚动,只是不卡界面的表现,事实上整个界面是完全无阻塞的,可以随时响应任何用户消息,就好像上面没有执行任何代码一样,但实际上后台在执行,而且是在异步执行,至于在异步执行后面的同步等待,在.NET4.5里面被偷偷地注册到了异步后的回调方法中去了。所以整个按钮事件必须用async修饰,标识它是支持异步的,虽然看似是同步执行的一个事件,实际上微软偷偷将其作为异步执行在处理,自动处理里面的同步部分。
但是这个功能想要模拟,难度非常大,而.NET4.5不支持XP,因此又不敢去用。
[解决办法]
学习了,感谢分享
[解决办法]
对于第一种设想,同步中插入异步的,我打算让进度条窗口在另一个线程中运行,而UI线程就让它卡死,只是不给用户去点击,只能点击新开的窗口,这样用户体验就不会太糟糕。

对于第二种设想,我通过SynchronizationContext(同步上下文)实现了,在异步执行的方法中,穿插进来的所有同步操作,我发送到SynchronizationContext上面去操作,组织下代码格式后,看起来也很清晰。
[解决办法]
感谢分享,帮你顶下。
------解决方案--------------------


我不是写得很清楚了吗:“我打算让进度条窗口在另一个线程中运行”
那个是新建的STA线程,和后台线程有点不同,能够运行UI控件,你理解为一个程序同时开了2个不相干的窗口即可,进程显示的还是一个,但2个窗口互相之间不会干扰。虽然如此,但我可以通过设置静态变量来访问共享对象,进而干预另一个窗口。而这里也可以使用SynchronizationContext将这个线程的任务发送到另一个线程去执行,从而用户能够随时看到处理进度,但是界面却一直能响应。
[解决办法]
另外你说对winform不熟悉,其实论难度,WinForm < WebForm < WPF,既然你会WebForm,顺带学WinForm也完全没问题的。WinForm也只需要拖拖控件,不需要手写代码布局,代码布局得到WPF里面去做,所以WinForm简单,而WebForm有部分布局是要通过代码产生的,比如动态创建的html代码,还要考虑浏览器兼容性和运行速度,因此在界面设计上难度较大。而后台的事件响应3者基本相同,只是触发事件的模式不一样而已。
[解决办法]
SynchronizationContext使用起来方便,因为它的Send和Post是固定的参数,同时SynchronizationContext有通用性,不会因为WinForm或WPF而有差异。
你的这个代码其实写的不好,SynchronizationContext不应该迭代。
规范的代码编写方式是这样的:
先不管是否需要异步操作,按照同步操作编写代码。全部写好后,对其中的UI操作部分进行单独处理,添加

context.Post(t =>
{

},this);

如果是获取变量内容,则必须用Send请求。这里的模型甚至可以用代码生成器自动产生,前提是要添加#regin标签进行代码分类,便于识别。它的好处是可读写强。如果这里不传递this对象,为空也可以,但是执行效率会降低些,因为如果不是通过变量传递,直接访问外部变量的话,这个匿名委托的处理方式就会有不同,编译器会创建一个匿名类来传递外部变量的。
[解决办法]
sjdlkjasllfsavnlsakvskjdfasoiehdsnahasdhfalsdfhaslf

热点排行