none
有什么方法可以代替 Mutex 的功能,而也能节省资源。 RRS feed

  • 问题

  • 有什么别的方法可以实现 Mutex 的功能,也就是可以根据变量来创建同步的对象。

    不仅比较消耗资源而且如果一台机器同时运行多个一样的客户端成功,一个客户端的 Mutex 对象也会影响到其他的客户端的同步。


    Sherrys
    2009年4月16日 9:58

答案

  • 下面代码使用了我上面提供的  syncdictionary   其实在不需要对它作foreach的状况下 也可以用普通的dictionary


    其实同步最主要的方式   就是通过对资源的管理来限制




    using System;
    
    using System.Collections.Generic;
    
    using System.Linq;
    
    using System.Text;
    
    using System.ComponentModel;
    
    using System.ComponentModel.Design;
    
    using System.Runtime.InteropServices;
    
    using System.Diagnostics;
    
    using System.Threading;
    
    using System.Security.Permissions;
    
    
    
    namespace System.IO
    
    {
    
       public class SyncFileStream
    
    
    
        {
    
    
    
            private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    
           
    
            FileStream _Core;
    
            public  FileStream FileStream
    
            {
    
               get 
    
               {
    
                   _lock.EnterReadLock  ();
    
                   var rv= _Core;
    
                   _lock.ExitReadLock  ();
    
                   return rv;
    
               }
    
                private set 
    
                {
    
                    
    
                }
    
    
    
            }
    
               
    
            static  private  Collections.Generic.Sync.SyncDictionary <string,IO.SyncFileStream >_Coredic; 
    
    
    
     
    
            private  SyncFileStream(string path,System.IO.FileMode  mode,IO.FileAccess access)
    
            {
    
                _lock.EnterWriteLock();
    
                _Core = new FileStream(path.ToLower() , mode, access );
    
                
    
            }
    
    
    
            
    
    
    
            public void  Close()
    
            {
    
                _Core.Close();
    
                _Core.Dispose();
    
                _Core=null;
    
                _lock.ExitWriteLock ();
    
            
    
            }
    
    
    
    
    
            static public SyncFileStream CreateInstance(string path,System.IO.FileMode  mode,IO.FileAccess access)
    
            {
    
                SyncFileStream temp=null;
    
               
    
                if(_Coredic.TryGetValue(path.ToLower () ,out temp ))
    
                {
    
                    if (temp.FileStream==null)
    
                    {
    
                        temp._lock.EnterWriteLock();
    
                        temp.FileStream=new FileStream(path.ToLower() , mode, access );
    
                        
    
                    }
    
                   
    
                }
    
                else 
    
                {
    
                          temp=new SyncFileStream(path,mode,access);
    
                _Coredic.Add (path.ToLower () , temp ) 
    
                
    
                }
    
         
    
                return temp;
    
    
    
    
    
    
    
            }
    
                
    
                ;
    
    
    
        }
    
    }
    
    
    
    

    工作突然有点忙 嘿嘿
    • 已标记为答案 Sherrys 2009年4月17日 8:36
    2009年4月17日 8:14
    版主

全部回复

  • 你好!
         还可以使用事件和信号量
         也可以使用Monitor类和lock关键字实现同步!
         具体要根据你的具体需求来选择!
    周雪峰
    2009年4月16日 11:04
    版主
  • lock 都只能对 一个已经定义好的对象 来进行锁定。
    Event 也要在固定的操作里面进行 Set  Reset

    Mutex m = new Mutex("变量"); 可以根据传入的值来创建,可以创建N个同步的对象。

    lock Monitor Event 测试后都不能简单的实现这样的功能。

    不知道有什么好的思路可以提供实现。


    Sherrys
    2009年4月16日 11:16
  • 要不要考虑适配器模式 或者模板模式  把你要锁定的对象放在一个类里面包住?

    比如你看这个实现了对Dictionary 进行写入同步锁的类

    namespace System.Collections.Generic.Sync
    {
    
        public class SyncDictionaryAdapter<TKey, TValue> : IDictionary<TKey, TValue>
        {
            private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
            Dictionary<TKey, TValue> BaseDictionary { get; set; }
            private   ICollection<KeyValuePair<TKey, TValue>> BaseCollection
            {
                get
                { return (ICollection<KeyValuePair<TKey, TValue>>)BaseDictionary; }
               
            }
            public SyncDictionaryAdapter(Dictionary<TKey, TValue> Dictionary)
            {
                BaseDictionary = Dictionary;
            }
    
    
    
    
    
    
    
    
            #region IDictionary<TKey,TValue> Members
    
            public void Add(TKey key, TValue value)
            {
                _lock.EnterWriteLock();
                BaseDictionary.Add(key, value);
                _lock.ExitWriteLock();
            }
    
            public bool ContainsKey(TKey key)
            {
                 
                _lock.EnterReadLock();
                var rv = BaseDictionary .ContainsKey(key);
                _lock.ExitReadLock();
                return rv;
            }
    
            public ICollection<TKey> Keys
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary.Keys;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public bool Remove(TKey key)
            {
                _lock.EnterWriteLock();
                var rv = BaseDictionary.Remove(key);
                _lock.ExitWriteLock();
                return rv;
            }
    
            public bool TryGetValue(TKey key, out TValue value)
            {
                _lock.EnterReadLock();
                var rv = BaseDictionary.TryGetValue(key, out value);
                _lock.ExitReadLock();
                return rv;
            }
    
            public ICollection<TValue> Values
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary.Values;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public TValue this[TKey key]
            {
                get
                {
                    _lock.EnterReadLock();
                    var rv = BaseDictionary[key];
                    _lock.ExitReadLock();
                    return rv;
                }
                set
                {
                    _lock.EnterWriteLock();
                    BaseDictionary[key] = value;
                    _lock.ExitWriteLock();
    
                }
            }
    
            #endregion
    
            #region ICollection<KeyValuePair<TKey,TValue>> Members
    
            public void Add(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterWriteLock();
                BaseCollection.Add(item);
                _lock.ExitWriteLock ();
              
            }
    
            public void Clear()
            {
                _lock.EnterWriteLock();
                BaseCollection.Clear ();
                _lock.ExitWriteLock();
            }
    
            public bool Contains(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterReadLock ();
                var rv = BaseCollection.Contains(item);
                _lock.ExitReadLock ();
                return rv;
    
            }
    
            public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
            {
                _lock.EnterReadLock();
                BaseCollection.CopyTo(array, arrayIndex);
                _lock.ExitReadLock();
            }
    
            public int Count
            {
                get {
                    _lock.EnterReadLock();
                    var rv = BaseCollection.Count;
                    _lock.ExitReadLock();
                    return rv;
                }
            }
    
            public bool IsReadOnly
            {
                get
                {
    
                    return BaseCollection.IsReadOnly;
    
                }
            }
    
            public bool Remove(KeyValuePair<TKey, TValue> item)
            {
                _lock.EnterWriteLock ();
                var rv = BaseCollection.Remove(item);
                _lock.ExitWriteLock();
                return rv;
            }
    
            #endregion
    
            #region IEnumerable<KeyValuePair<TKey,TValue>> Members
    
            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
            {
                return BaseDictionary.GetEnumerator();
            }
    
            #endregion
    
            #region IEnumerable Members
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return BaseDictionary.GetEnumerator();
            }
    
            #endregion
        }
    }

    工作突然有点忙 嘿嘿
    2009年4月17日 1:39
    版主
  • @韦恩卑鄙

    你的实现方式还是蛮好的,不过我需要的不是一个集合里面的同步。

    举个小 case

    比如我现在有 80 线程在工作,然后每个线程需要写不同的文件,当然这 80 个线程不是都向同一个文件夹或者文本写内容,否则一个同步元就可以解决了。

    现在的问题就是 80 个线程可能根据不同的逻辑条件会写入到不同的目录与文本里面,而当其中有 10 个线程都在写同一个文本 A 的时候,那么这 10 个线程之间就需要保持同步,而其他的 70 个线程同样也有这样的规律,而且写到什么文件夹与文本是不定的,比如下个时间段,会根据一些条件,写入到另外的新目录与新的文本中,所以也就是我所说的这个“变量”要同步。

    Mutex 确实可以实现这个功能,但是由于线程比较多,导致吃掉的资料非常多,而且几个客户端都同时运行的话,Mutex 对象也会影响到别的客户端程序。

    所以现在希望找到更好的方式。

    Sherrys
    2009年4月17日 6:33
  • 首先 80个限程本身是有点夸张了  要不要考虑用异步的方式或者线城池任务排队呢?  要知道一个双核cpu每次只能运行两个线城  而且.net每个先程要应付1mb的线程控制信息  很消耗阿。。。


    以上是建议  但是不是解决问题的办法



    我建议你集中管理所有的文件流产生
    建立一个类

     

    class SyncFileStream:System.IO.Stream
    里面包含一个 filestream

    并且在 自己open的时候为自己增加写入锁  close的时候解除写入锁

    再建立一个工厂方法 

    这个工厂方法
    会把所有已经打开的SyncFileStream流放入一个静态字典(也是对象池)  
    如果这个字典中的SyncFileStreamy已经打开  那么这个线程就可以被SyncFileStream写入锁所住 直到上一个close结束

    不知道说明白没有哦







    工作突然有点忙 嘿嘿
    2009年4月17日 7:45
    版主
  • 下面代码使用了我上面提供的  syncdictionary   其实在不需要对它作foreach的状况下 也可以用普通的dictionary


    其实同步最主要的方式   就是通过对资源的管理来限制




    using System;
    
    using System.Collections.Generic;
    
    using System.Linq;
    
    using System.Text;
    
    using System.ComponentModel;
    
    using System.ComponentModel.Design;
    
    using System.Runtime.InteropServices;
    
    using System.Diagnostics;
    
    using System.Threading;
    
    using System.Security.Permissions;
    
    
    
    namespace System.IO
    
    {
    
       public class SyncFileStream
    
    
    
        {
    
    
    
            private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    
           
    
            FileStream _Core;
    
            public  FileStream FileStream
    
            {
    
               get 
    
               {
    
                   _lock.EnterReadLock  ();
    
                   var rv= _Core;
    
                   _lock.ExitReadLock  ();
    
                   return rv;
    
               }
    
                private set 
    
                {
    
                    
    
                }
    
    
    
            }
    
               
    
            static  private  Collections.Generic.Sync.SyncDictionary <string,IO.SyncFileStream >_Coredic; 
    
    
    
     
    
            private  SyncFileStream(string path,System.IO.FileMode  mode,IO.FileAccess access)
    
            {
    
                _lock.EnterWriteLock();
    
                _Core = new FileStream(path.ToLower() , mode, access );
    
                
    
            }
    
    
    
            
    
    
    
            public void  Close()
    
            {
    
                _Core.Close();
    
                _Core.Dispose();
    
                _Core=null;
    
                _lock.ExitWriteLock ();
    
            
    
            }
    
    
    
    
    
            static public SyncFileStream CreateInstance(string path,System.IO.FileMode  mode,IO.FileAccess access)
    
            {
    
                SyncFileStream temp=null;
    
               
    
                if(_Coredic.TryGetValue(path.ToLower () ,out temp ))
    
                {
    
                    if (temp.FileStream==null)
    
                    {
    
                        temp._lock.EnterWriteLock();
    
                        temp.FileStream=new FileStream(path.ToLower() , mode, access );
    
                        
    
                    }
    
                   
    
                }
    
                else 
    
                {
    
                          temp=new SyncFileStream(path,mode,access);
    
                _Coredic.Add (path.ToLower () , temp ) 
    
                
    
                }
    
         
    
                return temp;
    
    
    
    
    
    
    
            }
    
                
    
                ;
    
    
    
        }
    
    }
    
    
    
    

    工作突然有点忙 嘿嘿
    • 已标记为答案 Sherrys 2009年4月17日 8:36
    2009年4月17日 8:14
    版主
  • 在客户端程序运行上百的线程非常常见的事情了,不过上面写文件只是举个例子,可能小于 80 线程,也可能大于 80 线程,至于你说双核 CPU 只能运行两个线程的说法不太理解所以不太赞成。说回这个问题吧。

    你说的通过一个字典创建一个对象池的方式有考虑过,但是好像并不可行。

    比如一个装订书本的工厂,同样我使用 80 个线程来装订一个车间的书(100-800 编号),线程会根据书的特征来自动的分配由哪几个线程装订同一本书籍,如果 1-5 号线程正在装订 100 编号的书,6-10 线程在装订 101 编号的书,在这个时候还会别的部分不断的往这个车间添加其他编号的书籍比如 900 - 1000 号,那么程序会根据当前工作量的大小,重新分配新的线程来完成别的书籍,比如就会动态的增加 10 个线程进行操作,这些都是动态的。。 因为在装订某本书的时候里面会有一些操作需要它所在的线程例如 1-5 号线程同步进行某一个环节,然后再继续干自己的事情,那么我现在创建一个字典为 dic 然后 Add("1-5,100",同步对象) 然后每次执行到需要同步操作的时候就 lock(dic["1-5,100"]) 这样不能确定是锁的 dic 里面的对象呢,还是锁的 dic 本身,而且如果这样还存在一个问题,dic 会被所有线程使用,当1-5号线程正在 lock(dic["1-5,100"])  的时候, 6-10 线程可能正在装订另外的书籍,正需要 Add 一个新的对象进行同步,那样会不会存在问题呢,因为刚 1-5 号线程与 6-10 号线程分别装订自己的书籍时,他们之间是不会有任何影响,也就是不要产生任何同步的。


    Sherrys
    2009年4月17日 8:21
  • 上面创建文件流的例子,是蛮不错的方式。
    Sherrys
    2009年4月17日 8:37
  • 呵呵  能帮得上你的话我也没白写啊  :D 

    dic 是前一阵子自己需要写的

    filestream 是刚刚害怕自己没说清楚  现写的



    线程 同时运行数 就是非阻塞状态的活跃线程运行的数目    一般有几个核  就有几个运算线程

    如果你的程序是运算程序    那么超出这个总数就毫无意义   不如自己分配到这么多个线程中去计算  或者干脆用.net线城池队列

    如果程序主要卡在io上 比如socket 软盘 磁带机  那阻塞的线程那1mb内存就全浪费掉了 不如用异步,因为 .net的io都用的完成端口  读取阻塞本身不占用线程


    工作突然有点忙 嘿嘿
    2009年4月17日 9:06
    版主
  • 按你的这个思路,改进一下,应该可以解决我的这个问题。辛苦辛苦。

    如果你说的是运算的速度的话,这样说我还是理解的,多线程是为了异步的去执行多个操作,而不需要排队等待,这样会提高工作的效率。当然计算的速度还是靠 CPU 说的算,再多线程也不可能操作 CPU 本身的限制的。


    Sherrys
    2009年4月17日 9:17