很久不写了,原因是自己很懒。本来打算把前段时间在台湾弄的GoogleMap的总结一下。可是那边用的vs2008回来我的电脑装的都是2005,又懒得把程序转化了。呵~
 最近需要几个功能用到了多线程、异步、等等总结一下。会说的一下几个问题:
1、前台UI响应后开个其他的线程干别的。
2、每隔一段时间做点事
3、非UI线程咋访问UI上的控件啊。
4. Timer类原来有好几个啊。


1.这个是我UI的响应一下后要异步的执行一个东东。多线程、异步看的糊里糊涂,看到一句话说的挺好的“异步是目的,多线程是手段”大有拨开云雾见日出的意思。
这里我用的是线程池。将线程安放在线程池里,需使用ThreadPool.QueueUserWorkItem()方法,该方法的原型如下:
//将一个线程放进线程池,该线程的Start()方法将调用WaitCallback代理对象代表的函数
public static bool QueueUserWorkItem(WaitCallback);
//重载的方法如下,参数object将传递给WaitCallback所代表的方法
public static bool QueueUserWorkItem(WaitCallback, object);
注意: ThreadPool类是一个静态类,你不能也不必要生成它的对象。而且一旦使用该方法在线程池中添加了一个项目,那么该项目将是无法取消的。在这里你无需自己建立线程,只需把你要做的工作写成函数,然后作为参数传递给ThreadPool.QueueUserWorkItem()方法就行了,传递的方法就是依靠WaitCallback代理对象,而线程的建立、管理、运行等工作都是由系统自动完成的,你无须考虑那些复杂的细节问题。

代码如下:    
   private void Send()      
  {            
     ThreadPool.QueueUserWorkItem(new WaitCallback(SendRecord));//无参数                      ThreadPool.QueueUserWorkItem(new WaitCallback(SendRecord),"参数");//有参数。      
  }       
  private void SendRecord(object obj)            //定义这个函数的时候必有object的参数       
  {           
   Thread.Sleep(3000);      
  }
调用这个异步执行的时候就用Send(),而真正要干的代码放在SendRecord()里面。


2. 我还需要每隔一段时间干点啥,这里用的是Threading.timer。 
System.Threading.Timer 是一个使用回调方法的计时器,而且由线程池线程服务,简单且对资源要求不高。  
只要在使用 Timer,就必须保留对它的引用。对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。
即使 Timer 仍处在活动状态,也会被回收。当不再需要计时器时,请使用 Dispose 方法释放计时器持有的资源。
使用 TimerCallback 委托指定希望 Timer 执行的方法。计时器委托在构造计时器时指定,并且不能更改。此方法不在创建计时器的线程中执行,而是在系统提供的线程池线程中执行。  
Timer timer = new Timer(timerDelegate, s,1000, 1000);

// 第一个参数:指定了TimerCallback 委托,表示要执行的方法;
// 第二个参数:一个包含回调方法要使用的信息的对象,或者为空引用;
// 第三个参数:延迟时间——计时开始的时刻距现在的时间,单位是毫秒,指定为“0”表示立即启动计时器;
// 第四个参数:定时器的时间间隔——计时开始以后,每隔这么长的一段时间,TimerCallback所代表的方法将被
Timer.Change()方法:修改定时器的设置。(这是一个参数类型重载的方法)
代码如下:
public Form1()
        {
            InitializeComponent();
            TimerExampleState s = new TimerExampleState();
            //创建代理对象TimerCallback,该代理将被定时调用
            TimerCallback timerDelegate = new TimerCallback(CheckStatus);
            //创建一个时间间隔为1s的定时器
            System.Threading.Timer timer = new System.Threading.Timer(timerDelegate, s, 1000, 1000);
            s.tmr = timer;
        }
  void CheckStatus(Object state)
        {
            TimerExampleState s = (TimerExampleState)state;
            s.counter++;
            Console.WriteLine("{0} Checking Status {1}.", DateTime.Now.TimeOfDay, s.counter);

            if (s.counter == 5)
            {
                //使用Change方法改变了时间间隔
                (s.tmr).Change(10000, 2000);
                Console.WriteLine("changed");
            }

            if (s.counter == 10)
            {
                //Console.WriteLine("disposing of timer");
                s.tmr.Dispose();
                s.tmr = null;
            }
        }
class TimerExampleState
    {
        public int counter = 0;
        public System.Threading.Timer tmr;
    }
    这个是在form已出现就开始记时了,实际用的时候就在需要的时候创建timer。
当到达调度时刻时,System.Threading.Timer 将异步调用由TimerCallback参数指定的回调方法。也就是说TimerCallback所指向的方法将在.NET Thread Pool中的工作者线程中执行。


3、以前把一个03的程序改成05的时候就遇到了这种问题。这次我没隔一段时执行的代码中有时候会有个反馈到UI上,就又遇到这个问题。看到大家的解决方案主要有:
第一:
Control.CheckForIllegalCrossThreadCalls = false;
线程开始的时候加这么一句,OK,看不到错误了~
啥都能用了~

第二:
用委托,在05里,每个控件都有个InvokeRequired的属性~
判断一下是不是true,是的话进行Invoke操作的,完事了~
但是第一种方法只是简单的将错误提示禁用了,仍然存在跨线程调用控件的问题。为此可能造成两个线程同时或者循环改变该控件的状态导致线程死锁。
Invoke方法是同步的方法,所以执行过程是有先后顺序的,所以就不会出现那个异常了
代码如下:
 //建立个委托
        private delegate void TestDelegate();

        //实际的操作
        private void returnSchool()
        {
            this.textBox1.Text = "xx"+i.ToString();
        }

        //判断一下是不是该用Invoke滴~,不是就直接返回~
        private void returnCB(TestDelegate myDelegate)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(myDelegate);
            }
            else
            {
                myDelegate();
            }
        }
 //在第一个问题的代码里面调用
  private void SendRecord(object obj)
        {
            Thread.Sleep(3000);
            returnCB(returnSchool);
        }
号外:是不是BackgroundWorker可以完成我上述的两个功能呢?DoWork事件,可以把耗时操作绑定到该事件。RunWorkerCompleted事件,当DoWork事件响应函数结束后该事件被触发,并且可以通过事件参数的e.result得到DoWork中设置的e.result。
有时间去想一想。。


4、
关于C#中timer类  在C#里关于定时器类就有3个  
1.定义在System.Windows.Forms里  
2.定义在System.Threading.Timer类里  
3.定义在System.Timers.Timer类里 
System.Windows.Forms.Timer是应用于WinForm中的,它是通过Windows消息机制实现的,类似于VB或Delphi中的Timer控件,内部使用API  SetTimer实现的。它的主要缺点是计时不精确,而且必须有消息循环,Console  Application(控制台应用程序)无法使用。  
 
System.Timers.Timer和System.Threading.Timer非常类似,它们是通过.NET  Thread  Pool实现的,轻量,计时精确,对应用程序、消息没有特别的要求。System.Timers.Timer还可以应用于WinForm,完全取代上面的Timer控件。它们的缺点是不支持直接的拖放,需要手工编码。

System.Timers.Timer定时器不同于System.Windows.Forms.Timer定时器,System.Timers.Timer定时器的定时事件的响应函数并不是在调用定时器Start方法的线程中去执行。

好吧,简单记录一下,又遇到新问题再去研究~~。。。

posted on 2008-09-11 17:31  风孤鸿  阅读(1270)  评论(1编辑  收藏  举报