• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

《CLR Via C# 第3版》笔记之(二十) - 计时器及伪共享

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

计时器在很多应用场景中广泛应用,System.Threading命名空间下,有个Timer类可以完成计时器的操作。

下面来讨论下Timer类的使用及多个CPU内核同时运行线程时如何共享高速缓存(cache)的。

主要内容:

  • 计时器的使用
  • CPU高速缓存的伪共享

 

1. 计时器的使用

1.1 计时器的创建及改变设置

计时器创建的API都类似,有以下5种:

1
2
3
4
5
public Timer(TimerCallback callback);
public Timer(TimerCallback callback, object state, int dueTime, int period);
public Timer(TimerCallback callback, object state, long dueTime, long period);
public Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period);
public Timer(TimerCallback callback, object state, uint dueTime, uint period);

其中各个参数的含义如下:

  1. callback:定时执行的操作
  2. state:传递给callback的参数
  3. dueTime:首次调用callback时,需要等待多少毫秒
  4. period:每隔多少毫秒执行一次callback

 

下面例子演示如何创建一个计时器,并且在运行10秒后如何改变计时器的dueTimeperiod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Threading;
 
public class CLRviaCSharp_20
{
    static void Main(string[] args)
    {
        // 定义一个定时器,每2秒执行一次
        Timer t = new Timer(PrintTime, "Timer Test", 0, 2000);
 
        // 主线程等待10秒(让计时器先执行6次)
        Thread.Sleep(10000);
 
        // 改变计时器的设置,停3秒后,每2秒执行一次
        t.Change(3000, 1000);
        Console.ReadKey(true);
    }
 
    private static void PrintTime(object state)
    {
        Thread.Sleep(3000);
        Console.WriteLine("{0}: Now is {1}", state, DateTime.Now);
    }
}

运行上面的例子,我们发现有以下现象:

  1. 刚开始每隔2秒打印一次当前时间
  2. 10秒后,每隔1秒打印一次当前时间
  3. callback(即PrintTime函数)中虽然有Sleep(3000);但计时器的下一次callback并没有等待本次callback完成就开始运行了。

对于上述的第三点,是由于Timer在每个period到期时,如果上个callback没完成,会在线程池中再启动一个线程来完成本次的callback。

 

1.2 耗时操作(操作消耗的时间 > 计时器的时间间隔)

但是,对于某些应用场景,可能需要callback一个一个顺序执行。

如果callback的耗时较长,希望下次callback能在本次callback完成后,再过period后执行。这时,就需要我们使用TimerChange方法实现。

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
using System;
using System.Threading;
 
public class CLRviaCSharp_20
{
    static Timer t;
 
    static void Main(string[] args)
    {
        // 定义一个计时器,
        // period参数设置为Timeout.Infinite的意思是计时器执行一次就结束
        t = new Timer(PrintTime, "Timer Test", 0, Timeout.Infinite);
        Console.ReadKey(true);
    }
 
    private static void PrintTime(object state)
    {
        Thread.Sleep(3000);
        Console.WriteLine("{0}: Now is {1}", state, DateTime.Now);
 
        // 因为计时器执行一次就结束,所以在callback(即PrintTime)执行完后再启动一个计时器
        // 此计时器仍然设置period参数设置为Timeout.Infinite
        // 并且设置dueTime参数为2000毫秒,从而保证下次callback在本次callback完成2秒后执行
        // 这样不管每个callback耗用多少时间,两个callback之间的间隔时间始终是2秒
        t = new Timer(PrintTime, "Timer Test", 2000, Timeout.Infinite);

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
重新整理数据结构与算法(c#)——算法套路二分法[二十四]发布时间:2022-07-10
下一篇:
C#XML操作类XmlHelper发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap