attributes && reflections &&Thread&&Synchronization

 

1.属性和反射

属性是对目标元素的相关数据的代表。

同时C# 还具有一个反射系统,可用来检索用自定义属性定义的信息。(否则自定义属性没什么意义,不过老师说可以用一些软件来查看,比如书上说的:ILDasm)

老师讲的比较快,听得不是很清楚,后来翻了翻书,看到“自定义属性”的内容,进行了尝试。

这个例子是把程序的错误信息绑定到代码的特定修正中(特定修正?),然后利用反射将元数据输出到console流里。

 1 namespace CustomAttributes
 2 {
 3     //create attributes
 4     [AttributeUsage(AttributeTargets.Class|AttributeTargets.Constructor|AttributeTargets.Field
 5                     |AttributeTargets.Method|AttributeTargets.Property,AllowMultiple = true)]
 6     public class BugFixAttribute : System.Attribute
 7     {
 8         //private class member
 9         private int bugID;
10         private string comment;
11         private string date;
12         private string programmer;
13         //按声明顺序导入参数  构造函数
14         public BugFixAttribute(int bugID, string programmer, string date)
15         {
16             this.bugID = bugID;
17             this.programmer = programmer;
18             this.date = date;
19         }
20         //只读参数访问器
21         public int BugID
22         {
23             get { return bugID; }
24         }
25         //带名参数的特征
26         public string Comment
27         {
28             get { return comment; }
29             set { comment = value; }
30         }
31         public string Date
32         {
33             get { return date; }
34         }
35         public string Programmer
36         {
37             get { return programmer; }
38         }
39          
40     }
41     [BugFixAttribute(121,"mark","15/04/30")]
42     [BugFixAttribute(107,"mark","15/05/02",Comment= "fixed off by one error")]
43 
44     public class MyMath
45     {
46         public double f1(double p1)
47         {
48             return p1 + f2(p1);
49         }
50         public double f2(double p1)
51         {
52             return p1 / 3;
53         }
54     }
55     public class Tester
56     {
57         public static void Main ()
58         {
59             MyMath mm = new MyMath();
60             Console.WriteLine("call f(7).result:{0}", mm.f1(7));
61             
62             //获得成员信息并检索自定义属性
63             System.Reflection.MemberInfo inf = typeof(MyMath);
64             object[] attributes;
65             attributes = inf.GetCustomAttributes(typeof(BugFixAttribute), false);
66 
67             //遍历属性并检索
68             foreach( Object attribute in attributes)
69             {
70                 BugFixAttribute bfa = (BugFixAttribute)attribute;
71                 Console.WriteLine("\nBugID:{0},bfa {0}", bfa.BugID);
72                 Console.WriteLine("Programmer: {0}", bfa.Programmer);
73                 Console.WriteLine("Date: {0}", bfa.Date);
74                 Console.WriteLine("Comment: {0}", bfa.Comment);
75             }
76         }
77     }
78 }

结果为:

其中代码的后半段的反射所使用的主要方法是 GetCustomAttributes,它返回对象数组,这些对象在运行时等效于源代码属性。

 

2.线程与同步

1)创建线程

线程使程序在同一时间内做不同的事情。

多处理器:快(同时进行)

单处理器:慢(交替进行),来回切换

下面创建了2个线程,分别从0数到1000和从1000数到0

 1 public static void Main ()
 2         {
 3             Tester t = new Tester();
 4             Console.WriteLine("let us begin the threading testing!");
 5             t.DoTest();
 6 
 7         }
 8         public void DoTest()
 9         {
10             Thread t1 = new Thread(new ThreadStart(f1));
11             Thread t2 = new Thread(new ThreadStart(f2));
12             t1.Start();
13             t2.Start();
14         }
15         public void f1()
16         {
17             for(int i = 0; i < 1000; i++)
18             {
19                 System.Console.WriteLine("f1:{0}", i);
20             }
21         }
22         public void f2()
23         {
24             for (int i = 1000; i > 0; i--)
25             {
26                 System.Console.WriteLine("f2:{0}", i);
27             }
28         }

结果为:可知,两个线程是交替进行的。

2)拼接线程

把t2.Join();写入t1的一个函数里,运行时t1将会挂起等待知道t2结束。

3)通过睡眠阻塞线程

加Thread.Sleep(),会让线程有机会在另一个线程打印一个值的时候运行。例如将1)中加入sleep,则结果变为:

4)中断线程

推荐的方法:设置布尔标记KeepAlive,线程间隔地检测这个值,当标记改变状态时,线程可以自己停止自己。

(这是百度到的教程里的代码和讲解,感觉比课本里的清晰,但是好像用的是interrupt课本的略乱)

代码中声明了两个线程,创建两线程的委托实例,例子是输出从1到50的整数,并在输出10,20和30之后使线程睡眠;输出从51到99的整数,并自动检测线程sleeper的状态,当sleeper处于WaitSleepJoin时,调用Interrupt使其回到调度队列:

 1 public class SleepAndInterrupt
 2 
 3 {
 4   //声明两线程
 5     public static Thread sleeper;
 6     public static Thread interrupter;
 7     public static void Main()
 8     {
 9         Console.WriteLine("进入Main");
10         //创建两线程的委托实例
11         sleeper = new Thread(new ThreadStart(SleepThread));
12         interrupter = new Thread(new ThreadStart(InterruptThread));
13         //开始执行两线程
14       sleeper.Start();
15         interrupter.Start();
16         Console.WriteLine("退出Main");
17     }
18     //输出从1到50的整数,并在输出10,20和30之后使线程睡眠
19     public static void SleepThread()
20     {
21         for(int i = 1; i <= 50; i++)
22         {
23            Console.Write (i+" ");
24             if(i == 10 || i == 20 || i == 30)
25             {
26                 Console.WriteLine("在{0}处进入睡眠", i);
27                 //捕捉使线程睡眠抛出的异常
28                 try
29                 {
30                     Thread.Sleep(10);
31                 }
32                 catch
33                 {
34                 }
35             }
36         }
37     }
38     //输出从51到99的整数,并自动检测线程sleeper的状态
39     //当sleeper处于WaitSleepJoin时,调用Interrupt使其回到调度队列
40     public static void InterruptThread()
41     {
42         for(int i = 51; i < 100; i++)
43         {
44             Console.Write(i+" ");
45             //判断线程sleeper的当前状态
46             if(sleeper.ThreadState == System.Threading.ThreadState.WaitSleepJoin)
47             {
48                 Console.WriteLine("中断睡眠中的线程");
49                 sleeper.Interrupt();
50             }
51         }
52     }
53 }

结果为:

 5)同步

同步通过对对象加锁实现,帮助程序员阻止另一个线程闯入你的对象,知道第一个线程不再使用这个对象为止。

同步有三种方式:互锁类,c#lock语句,监控器器对象。

首先模拟一个共享资源:

 1 namespace SharedResource
 2  {
 3      class Tester
 4      {
 5          private int counter = 0;
 6           static void Main()
 7          {
 8              Tester t = new Tester();
 9              t.DoTest();
10          }
11          public void DoTest()
12           {
13               Thread t1 = new Thread(new ThreadStart(f1));
14               t1.IsBackground = true;
15               t1.Name = "threadOne";
16               t1.Start();
17               Console.WriteLine("Started thread {0}", t1.Name);
18               Thread t2 = new Thread(new ThreadStart(f1));
19               t2.IsBackground = true;
20               t2.Name = "threadOne";
21               t2.Start();
22               Console.WriteLine("Started thread {0}", t2.Name);
23 
24               t1.Join();
25               t2.Join();
26 
27              //所有线程结束后打印一个消息
28               Console.WriteLine("ALL thread are done.");
29           }
30          public void f1()
31          {
32              try
33              {
34                  while(counter < 1000)
35                  {
36                      int temp = counter;
37                      temp++;
38                      Thread.Sleep(1);
39 
40                      counter = temp;
41                      Console.WriteLine("Thread {0}.f1:{1}", Thread.CurrentThread.Name, counter);
42                  }
43              }
44              catch (ThreadInterruptedException)
45              {
46                  Console.WriteLine("thread{0} interrupted! Cleaning up...", Thread.CurrentThread.Name);
47 
48              }
49              finally
50              {
51                  Console.WriteLine("Thread{0} existing.", Thread.CurrentThread.Name);
52              }
53          }
54 
55      }
56  }

结果为:(部分)

然后使用互锁(Interlocked)

改变上文中方法的try语句

1              try
2              {
3                  while(counter < 1000)
4                  {
5                      int temp = Interlocked.Increment(ref counter);                  
6                      Thread.Sleep(0);
7                      Console.WriteLine("Thread {0}.f1:{1}", Thread.CurrentThread.Name, temp);
8                  }
9              }

结果为(部分):

此时对成员counter的访问就是同步的。

然后是更广泛使用的同步机制c#lock,其可以控制对其他对象的访问,其标记了代码中的一个临界区,当锁有效的时候对指定的对象提供同步机制。

将代码中try改为:

 1              try
 2              {
 3                  while(counter < 1000)
 4                  {
 5                      int temp;                  
 6                      Thread.Sleep(0);
 7                      lock(this)
 8                      {
 9                          temp = counter;
10                          temp++;
11                          Thread.Sleep(1);
12                          counter = temp;
13                      }
14                      Console.WriteLine("Thread {0}.f1:{1}", Thread.CurrentThread.Name, temp);
15                  }
16              }

输出与互锁相同。

 

over

 

posted @ 2015-05-01 09:14  marsh  阅读(255)  评论(1编辑  收藏  举报