线程安全的Generic Dictionary

简介:
  System.Collections.Generic.Dictionary<,>
只要不修改该集合, Dictionary   就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步。今天解决了使用Dictionary泛型类的时候出现一个错误 “System.InvalidOpervationException "集合已经修改,可能无法执行枚举操作"”。原来的代码如下:
         private   void  CheckingTimeout() 
        {
            List
< string >  list  =   new  List < string > ();
            
lock  (sessions)
            {
                
foreach  ( string  sessionKey  in  sessions.Keys)
                {
                    
if  (sessions[sessionKey].IsTimeouted) 
                    {
                        logger.Info(
" 会话 [ "   +  sessionKey  +   " ] 超时 " );
                        UnLoadSession(sessionKey);
                        list.Add(sessionKey);
                    }
                }
                
foreach  ( string  key  in  list)
                {
                    sessions.Remove(key);              
                }
            }
        } 

      
public   void  UnloadSession( string  sessionID)
        {
            
lock  (sessions)
            {
                
if  (sessions.ContainsKey(sessionID))
                {
                    db.Delete(GetSessionFromDatabase(sessionID));
                    dispatcher.UnregisterAllOutEventSubscriber(sessionID);
                    sessions.Remove(sessionID);
                }
            }
        }

错误出现的原因是代码中在枚举的过程中修改了集合,而造成了这个错误,修改后的代码如下:
 
       private void CheckingTimeout()
        {
            List
<string> list = new List<string>();
            
lock (sessions)
            {
                
foreach (string sessionKey in sessions.Keys)
                {
                    
if (sessions[sessionKey].IsTimeouted)
                    {
                        logger.Info(
"会话 [" + sessionKey + "] 超时");
                        UnregisterSession(sessionKey);
                        list.Add(sessionKey);
                    }
                }
                
foreach (string key in list)
                {
                    sessions.Remove(key);              
                }
            }
        }

        
private void UnregisterSession(string sessionID)
        {
            
lock (sessions)
            {
                
if (sessions.ContainsKey(sessionID))
                {
                    db.Delete(GetSessionFromDatabase(sessionID));
                    dispatcher.UnregisterAllOutEventSubscriber(sessionID);
                }
            }
        }
 




本文转自 张善友 51CTO博客,原文链接:http://blog.51cto.com/shanyou/75069,如需转载请自行联系原作者
目录
相关文章
|
存储 关系型数据库 MySQL
介绍一下MySQL的一些应用场景
【10月更文挑战第17天】介绍一下MySQL的一些应用场景
2826 0
|
存储 分布式计算 大数据
大数据的工具都有哪些?
【10月更文挑战第9天】大数据的工具都有哪些?
1130 1
|
存储 缓存 NoSQL
Redis从入门到精通之底层数据结构SDS(简单动态字符串)详解
SDS是Redis中的一种字符串类型,它是一种二进制安全的字符串,由简单动态字符串(SDS)实现。SDS支持多种数据结构,其中字符串(String)是最常用的一种数据结构之一。SDS的优点在于它可以避免C字符串常见的问题,比如缓冲区溢出和内存泄露等。SDS的常数复杂度获取字符串长度和杜绝缓冲区溢出可以避免使用strlen和strcat函数时的一些问题。同时,SDS的空间预分配和惰性空间释放两种策略可以减少修改字符串的内存重新分配次数。SDS也是二进制安全的,因为它不是以空字符串来判断字符串是否结束,而是以len属性表示的长度来判断字符串是否结束。SDS还兼容部分C字符串函数
3600 90
|
存储 缓存 编解码
FFmpeg开发笔记(七):ffmpeg解码音频保存为PCM并使用软件播放
FFmpeg开发笔记(七):ffmpeg解码音频保存为PCM并使用软件播放
FFmpeg开发笔记(七):ffmpeg解码音频保存为PCM并使用软件播放
TestEngine with ID ‘junit-jupiter‘ failed to discover tests异常问题处理
今天在接手的项目中本想在测试类中跑一遍持久层的逻辑,但是测试类型项目启动就报错
|
3天前
|
搜索推荐 编译器 Linux
一个可用于企业开发及通用跨平台的Makefile文件
一款适用于企业级开发的通用跨平台Makefile,支持C/C++混合编译、多目标输出(可执行文件、静态/动态库)、Release/Debug版本管理。配置简洁,仅需修改带`MF_CONFIGURE_`前缀的变量,支持脚本化配置与子Makefile管理,具备完善日志、错误提示和跨平台兼容性,附详细文档与示例,便于学习与集成。
269 116
|
18天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~