比如,DataTable对象,MSDN对它的线程安全性是这么说的:“该类型对于多线程读操作是安全的。 您必须使任何写操作同步。”
我要问的是:对于这种对象,在多线程环境下,是不是只需要对写操作进行lock,而不必对读操作进行lock,就可以保证线程安全 ?
还有Dictionary<TKey, TValue>,MSDN说的是:
只要不修改该集合,Dictionary<TKey, TValue> 就可以同时支持多个阅读器。 即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。 当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。 若允许多个线程对集合执行读写操作,您必须实现自己的同步。
是否也只需要对写操作进行lock,而不必对读操作进行lock,就可以保证线程安全 ?
那我再追问一下,我的一个全局静态DataTable,写操作是lock了的,那么在读取时,对它的Select方法返回DataRow[],或它的Rows集合,进行遍历操作,这两种情况,是否需要把遍历操作进行lock呢?
如果只是保证线程安全,只需要对写操作进行加锁就行了,多线程并行写一块内存是会出现内存错误的。
多个线程并行的读一块内存数据本身是不会出错的,但是会出现上下文不一致的设计上的问题。比如一个线程读取了数据在还没来得及显示出来时,原数据被另外一个线程改变了,等你显示出来的时候,显示的结果和原数据已经不一样了。为了保证上下文一致就读加锁。好像买火车票一样,一个人在买一张票,读取剩余票数还剩1张,结果在点击去确定的时候被已经被另外一个人(另一个线程)买走了。其实没有余票了,给了假象,读加锁就是防止这个出现的。
如果只是简单的刷新数据,比如上位机软件不断采集PLC数据保存到表中更新已有数据,那么多个线程就不需要加锁,因为所有线程只是为了把数据读取出来而已,为了保证数据的时时性,所有线程都竭力最快的读取上来。这个时候加锁,就变得跟单线程一样了。
当然前提是保证读取的数据存在,如果在一个线程准备读一个数据之前,数据被另一个线程删除了,这个删除不是清零是完全删除了BUFF,那么就会出错。关键根据你程序的需要来保证线程安全
当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。 若允许多个线程对集合执行读写操作,您必须实现自己的同步。
不是。特别对于枚举操作,在枚举过程中修改集合,可能会重置枚举器,从而造成访问冲突。
写操作包括:添加、删除、修改。
修改不影响读,但是删除会影响,而添加的话就要视集合实现添加的方式而定。
人家说的很清楚了,“若允许多个线程对集合执行读写操作,您必须实现自己的同步”。不光是写,多线程读,也要加锁。