摘要:
经常看到同事写代码: bool? obj=从服务器返回来的值,可能为null。 if(obj !=null && Convert.ToBoolean(obj)==true){ //Do something}上面的代码的意图很明显,先判断obj 是不是null,如果不是null 的话,再调用Convert.ToBoolean方法,判断是不是True。上面的方法没有任何问题,但有一点要确认的是, obj!=null 这句话需要判断吗?于是笔者写了下面的代码来对Convert的ToXXX方法传递null值进行测试。 可以看到,method.Invoke(null,new object 阅读全文
摘要:
线程安全的一个很经常的需求是允许并发读,但是不允许并发写,例如对于文件就是这样的。ReaderWriterLockSlim 在.net framework 3.5的时候就提供了,它是用来代替以前的”fat”版本的”ReaderWriterLock”这两个类,有两种基本的锁----一个读锁,一个写锁。写锁是一个完全排他锁。读锁可以和其他的读锁兼容因此当一个线程持有写锁的是很,所有的尝试获取读锁和写锁的线程全部阻塞,但是如果没有一个线程持有写锁,那么可以有一系列的线程并发的获取读锁。ReaderWriterLockSlim 定义了下面几个方法来获取和释放 读写锁。Public void Enter 阅读全文
摘要:
在上篇文章中我们使用了Wait和Pulse 实现了Countdown 接下来我们可以使用刚刚写的Countdown 类来实现两个线程的交会。 classRendezvous{staticobject_locker=newobject();staticCountdown_countdown=newCountdown(2);publicstaticvoidMainThread(){Randomr=newRandom();newThread(Mate).Start(r.Next(1000));Thread.Sleep(r.Next(10000));//主线程睡眠一段时间_countdown.Sing 阅读全文
摘要:
你可能在上篇文章中深入浅出多线程系列之十二:双向信号和竞赛 注意到了这个模式:两个Waiting 循环都要下面的构造:lock(_locker){while(!_flag)Monitor.Wait(_locker);_flag=false;}在这里_flag被另一线程设置为true。这是,从作用上讲,这里在模仿AutoResetEvent。如果我们将 _flag = false;去掉,那么我们就得到了一个基本的ManualResetEvent.让我们使用Wait和Pulse来为ManualResetEvent完成剩余的代码吧。 readonlyobject_locker=newobject() 阅读全文
摘要:
双向信号和竞赛(Two-Way Signaling and Races)Monitor.Pulse方法的一个重要特性是它是异步执行的,这意味着调用pulse方法并不会阻塞自己等待Monitor.Pulse返回。如果任何一个线程在pulsed 对象上等待,它是不会阻塞的,换句话说,调用Monitor.Pulse对程序不会有什么作用,你可以认为Monitor.Pulse方法被忽略了。这样Pulse提供了一个单向通信:一个 pulsing线程悄悄的向一个waiting 线程发送信号。Pulse并不会返回一个值来告诉你waiting线程是否收到信号。但是有时候我们需要知道waiting线程是否受到信号 阅读全文
摘要:
上次我们使用AutoResetEvent实现了一个生产/消费者队列。这一次我们要使用Wait和Pulse方法来实现一个更强大的版本,它允许多个消费者,每一个消费者都在自己的线程中运行。我们使用数组来跟踪线程。Thread[] _workers;通过跟踪线程可以让我们在所有的线程都结束后再结束我们的队列任务。每一个消费者线程都执行一个叫做Consume的方法,在一个for循环中,我们可以创建和启动线程。例如: publicPCQueue(intworkerCount){_workers=newThread[workerCount];for(inti=0;i<workerCount;i++) 阅读全文
摘要:
Signaling with Wait and Pulse(等待和暂停的信号)早期谈论过等待事件句柄(调用Wait的线程在没有收到另一个线程的通知前会一直阻塞)。Monitor借助它的静态方法Wait,Pulse,PulseAll提供了一个更给力的信号构造,使用这些方法和lock语句,你可以自己实现AutoResetEvent,ManualResetEvent和Semaphore。甚至WaitHandle的WaitAll和WaitAny方法了。怎样使用Wait 和Pulse ?1:定义一个同步对象,例如: Readonly object _locker=new object();2:定义自己的 阅读全文
摘要:
在大多数计算机上,增加变量操作不是一个原子操作,需要执行下列步骤: 1. 将实例变量中的值加载到寄存器中。2. 增加或减少该值。3. 在实例变量中存储该值。在多线程环境下,线程会在执行完前两个步骤后被抢先。然后由另一个线程执行所有三个步骤,当第一个线程重新开始执行时,它覆盖实例变量中的值,造成第二个线程执行增减操作的结果丢失。Interlocked可以为多个线程共享的变量提供原子操作。Interlocked.Increment:以原子操作的形式递增指定变量的值并存储结果。Interlocked.Decrement以原子操作的形式递减指定变量的值并存储结果。Interlocked.Add以原子操 阅读全文
摘要:
以前我们说过在一些简单的例子中,比如为一个字段赋值或递增该字段,我们需要对线程进行同步,虽然lock可以满足我们的需要,但是一个竞争锁一定会导致阻塞,然后忍受线程上下文切换和调度的开销,在一些高并发和性能比较关键的地方,这些是不能忍受的。.net framework 提供了非阻塞同步构造,为一些简单的操作提高了性能,它甚至都没有阻塞,暂停,和等待线程。Memory Barriers and Volatility (内存栅栏和易失字段 )考虑下下面的代码: int_answer;bool_complete;voidA(){_answer=123;_complete=true;}voidB(){i 阅读全文
摘要:
在Framework中存在着4种定时器:其中分为两类,多线程计时器1:System.Threading.Timer2:System.Timers.Timer特殊目的的单线程计时器:1:System.Windows.Forms.Timer(Windows Forms Timer)2:System.Windows.Threading.DispatcherTimer(WPF timer);多线程计时器比较强大,精确,而且可扩展性强;单线程计时器比较安全,对于更新 Windows Forms controls或者WPF这种简单任务来说更方便。System.Threading.Timer是最简单的多线程 阅读全文