• c#多线程实现定时执行代码与lock锁操作


    总结以下三种方法,实现c#每隔一段时间执行代码:

    方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间;

    方法二:使用System.Timers.Timer类;

    方法三:使用System.Threading.Timer;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    using System;
    using System.Collections;
    using System.Threading;
     
    public class Test
    {
     
        public static void Main()
        {
            Test obj = new Test();
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
     
            //方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间
            Thread thread = new Thread(new ThreadStart(obj.Method1));
            thread.Start();
     
     
            //方法二:使用System.Timers.Timer类
            System.Timers.Timer t = new System.Timers.Timer(100);//实例化Timer类,设置时间间隔
            t.Elapsed += new System.Timers.ElapsedEventHandler(obj.Method2);//到达时间的时候执行事件
            t.AutoReset = true;//设置是执行一次(false)还是一直执行(true)
            t.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件
            while (true)
            {
                Console.WriteLine("test_" + Thread.CurrentThread.ManagedThreadId.ToString());
                Thread.Sleep(100);
            }
     
     
            //方法三:使用System.Threading.Timer
            //Timer构造函数参数说明:
            //Callback:一个 TimerCallback 委托,表示要执行的方法。
            //State:一个包含回调方法要使用的信息的对象,或者为空引用(Visual Basic 中为 Nothing)。
            //dueTime:调用 callback 之前延迟的时间量(以毫秒为单位)。指定 Timeout.Infinite 以防止计时器开始计时。指定零 (0) 以立即启动计时器。
            //Period:调用 callback 的时间间隔(以毫秒为单位)。指定 Timeout.Infinite 可以禁用定期终止。
            System.Threading.Timer threadTimer = new System.Threading.Timer(new System.Threading.TimerCallback(obj.Method3), null, 0, 100);
            while (true)
            {
                Console.WriteLine("test_" + Thread.CurrentThread.ManagedThreadId.ToString());
                Thread.Sleep(100);
            }
     
            Console.ReadLine();
        }
     
     
        void Method1()
        {
            while (true)
            {
                Console.WriteLine(DateTime.Now.ToString() + "_" + Thread.CurrentThread.ManagedThreadId.ToString());
                Thread.CurrentThread.Join(100);//阻止设定时间
            }
        }
     
     
        void Method2(object source, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine(DateTime.Now.ToString() + "_" + Thread.CurrentThread.ManagedThreadId.ToString());
        }
     
     
        void Method3(Object state)
        {
            Console.WriteLine(DateTime.Now.ToString() + "_" + Thread.CurrentThread.ManagedThreadId.ToString());
        }
    }

    参考:

    http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813928.html

    http://www.cnblogs.com/zxtceq/p/5667281.html

    ================================================================================

    System.Threading.Timer   fTimer = new System.Threading.Timer(new TimerCallback(TaskService.DoTask), new AutoResetEvent(false), 0, 1000);
            public void DoTask(Object stateInfo)
            {
                lock (this)
                {
                    //任务代码
                }
            }

      当我 fTimer.Dispose();//停止了时间后,可以 任务代码 还在执行。经过我调式N次发现是在lock里阻塞了线程。当我
    fTimer.Dispose()停止后即使把fTimer = null ;   //任务代码 还是在执行。。。。我想问我怎么做 才可以把这些阻塞了线程立刻释放掉。简单的意思就是立刻停止它?

    -----------------------------------------------------------

    #16 得分:55回复于: 2008-05-07 19:16:48

    LZ是这样的:你的fTimer每秒钟都会调用一次DoTask,且同一时间只会有一个DoTask在运行,如果此时已有一个DoTask在运行,那么后面的将被lock在那里等着
    LZ你这么做一是为了同一时间只做一个DoTask,二是为了保证执行的顺序吧?
    实际上,当DoTask里的操作超过1秒时,后面的DoTask都会被lock在那里。比如我的fTimer运行了9秒多,那么应该有总共10个DoTask,假设DoTask要执行2秒钟,那么当你在9秒多停止fTimer的时候,实际上才运行到第5个DoTask(左右),后面还有5个DoTask被lock着呢
    LZ可以看下这个
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                Test t = new Test();
                while (t.Enabled) ;
                Console.WriteLine("STOPING:" + t.Value);
                t.Stop();
                Console.WriteLine("STOPPED:" + t.Value);
                Console.ReadLine();
            }
        }
        public class Test
        {
            System.Threading.Timer fTimer;
            private int i = 0;
            System.Timers.Timer timer;
    
            public int Value
            {
                get
                {
                    return i;
                }
            }
            public bool Enabled
            {
                get
                {
                    return timer.Enabled;
                }
            }
    
            public Test()
            {
                fTimer = new System.Threading.Timer(new TimerCallback(this.DoTask), new AutoResetEvent(false), 0, 1000);
                timer = new System.Timers.Timer(10000);
                timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
                timer.Enabled = true;
            }
    
            private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                timer.Enabled = false;
            }
    
            public void DoTask(Object stateInfo)
            {
                lock (this)
                {
                    Console.WriteLine(i++);
                    Thread.Sleep(2000);
                }
            }
    
            public void Stop()
            {
                fTimer.Dispose();
            }
        }
    }
    

    -------------------------------------------------

    1、下面只解释你的问题,并不是达到你目的的最好方法。

    2、Threading.Timer的工作方式是这样的。每次时钟到点时,Timer从线程池中取出一个线程来运行回调函数。如果该回调函数在下次时钟到点前还没来得及结束,那么,可能会有多个线程同时在执行该函数。如果线程池中没有空闲的线程可用,回调函数就要排队等候。

    3、Timer被取消后,它就不再安排新的回调函数,但是已经在运行的,或已经在排队的回调函数并没有被取消。所以当你fTimer.Dispose();停止了时间后,任务代码还在执行。

    4、改进的方法。首先判断一下当前线程池中剩余可用线程的数目,如果小于一定数量,回调函数立刻返回。这样可以减少排队的回调函数。
    其次,设置一个‘工作中’的标志,如果回调函数看到该标志被放倒了,它也应该立刻返回。

    5、即使经过如上改进后,Timer被取消后,线程池中线程也不会立刻完成 - 正在做‘任务代码’的那个线程得把任务作完了才有机会观察到‘工作中’标志。不过从这时起,所有回调函数将迅速返回。

    6、如果你程序退出了,线程池整个就被停止了,当然你所有的任务代码也就被停止了。如果你的任务代码没有需要清理的东西,这也是一种关闭方式。

        class TaskService
        {
            volatile bool running = true;
    
            public void DoTask(Object stateInfo)
            {
                int threadsLeft, dummy;
                ThreadPool.GetAvailableThreads(out threadsLeft, out dummy);
                if (threadsLeft < 2) return;          //<----
    
                lock (this)
                {
                    if (!running) return;             //<----
                    //任务代码 
                            }
            }
    
            public void test()
            {
                using (System.Threading.Timer fTimer = new Timer(new TimerCallback(DoTask), null, 0, 1000))
                {
                    Console.ReadLine();
    
                    fTimer.Change(0, Timeout.Infinite);
                    running = false;
                }
                Console.ReadLine();        
            }
    
            static void Main()
            {
                new TaskService().test();
            }
        }
    

    没有用lock和Timer的方法:

        volatile bool running = true;
    
        public void DoTasks()
        {
            DateTime last = new DateTime();
            
            while (running)
            {
                DateTime current = DateTime.Now;
                int elasped = (int) (current - last).TotalMilliseconds;
                last = current;
    
                if (elasped < 1000)
                {
                    Thread.Sleep(Math.Min(1000, 1000 - elasped));
                }
                //任务代码...
            }
        }

    出处:http://bbs.csdn.net/topics/220079236/

    以上信息只筛选一部分,查看完整版的可以直接查看出处给出的地址。

  • 相关阅读:
    Apache中Cookie长度的设置 414 request-uri too large apache
    URL中文参数,JSON转换,PHP赋值JS
    PHP通过JSON给JS赋值;JS通过JSON给PHP传值
    PHP限制上传文件大小
    PHP 类中使用全局变量和全局常量
    利用span设置文字固定宽度
    Linux用户管理
    DropZone(文件上传插件)
    rest_framework基础
    RESTful规范
  • 原文地址:https://www.cnblogs.com/mq0036/p/6474406.html
Copyright © 2020-2023  润新知