1.
表达式
|
类型
|
计算方法
|
结果( num1 的值为 5)
|
num2 = ++num1;
|
前置
自加
|
num1 = num1 + 1;
num2 = num1;
|
num2 = 6;
num1 = 6;
|
num2 = num1++;
|
后置
自加
|
num2 = num1;
num1 = num1 + 1; |
num2 = 5;
num1 = 6;
|
num2 = --num1;
|
前置
自减
|
num1 = num1 - 1;
num2 = num1;
|
num2 = 4;
Num1 = 4;
|
num2 = num1--;
|
后置
自减
|
num2 = num1;
num1 = num1 - 1; |
num2 = 5;
Num1 = 4;
|
2. 线程的安全性-实现线程同步
lock是C#关键词,它将语句块标记为临界区,确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。方法是获取给定对象的互斥锁,执行语句,然后释放该锁。
MSDN上给出了使用lock时的注意事项通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则。
1)如果实例可以被公共访问,将出现 lock (this) 问题。
2)如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题由于一个类的所有实例都只有一个类型对象(该对象是typeof的返回结果),锁定它,就锁定了该对象的所有实例。微软现在建议不要使用 lock(typeof(MyType)),因为锁定类型对象是个很缓慢的过程,并且类中的其他线程、甚至在同一个应用程序域中运行的其他程序都可以访问 该类型对象,因此,它们就有可能代替您锁定类型对象,完全阻止您的执行,从而导致你自己的代码的挂起。
3)由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。这个问题和.NET Framework创建字符串的机制有关系,如果两个string变量值都是"myLock",在内存中会指向同一字符串对象。
最佳做法是定义 private 对象来锁定, 或 private static对象变量来保护所有实例所共有的数据。
我们再来通过IL Dasm看看lock关键字的本质,下面是一段简单的测试代码:
{
int i = 5;
}
用IL Dasm打开编译后的文件,上面的语句块生成的IL代码为:
IL_004a: nop
.try
{
IL_004b: nop
IL_004c: ldc.i4.5
IL_004d: stloc.1
IL_004e: nop
IL_004f: leave.s IL_0059
} // end .try
finally
{
IL_0051: ldloc.3
IL_0052: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_0057: nop
IL_0058: endfinally
} // end handler
通过上面的代码我们很清楚的看到:lock关键字其实就是对Monitor类的Enter()和Exit()方法的封装,并通过try...catch...finally语句块确保在lock语句块结束后执行Monitor.Exit()方法,释放互斥锁。