项目中有块实时监控的内容,大概意思是一个线程负责把符合条件的值保存到Hashtable中,另一个线程不断的从这个Hashtable中读取数据,在这个过程中俩个线程同时操作Hashtable会报错误,从网上找了好多资料都没有解决,请各位高手帮忙!
下面是运行时会错的代码,请各位高手在次代码上进行修改:
using System;
using System.Collections;
using System.Threading;
using System.Collections.Generic;
using System.Text;namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            test t = new test();
            t.Start();
        }
    }
    public class test
    {
        Hashtable hs = new Hashtable();
        Thread thHsAdd = null;
        Thread thHsWrite = null;
        int index = 0;
        public void Start()
        {
            thHsAdd = new Thread(new ThreadStart(this.HsAdd));
            thHsAdd.Start();
            thHsWrite = new Thread(new ThreadStart(this.HsWrite));
            thHsWrite.Start();
        }
        public void HsAdd()
        {
            while (true)
            {
                hs.Add(index, DateTime.Now.ToString());
                index++;
                Thread.Sleep(1000);
            }
        }
        public void HsWrite()
        {
            while (true)
            {
                IDictionaryEnumerator ie = hs.GetEnumerator();
                while (ie.MoveNext())
                {
                    Console.WriteLine("key={0},value={1}", ie.Key, ie.Value);
                    Thread.Sleep(1000);
                }
            }
        }
    }
}

解决方案 »

  1.   

    lock试试,write也lock        public void HsAdd() {
                lock (hs) {
                    while (true) {
                        hs.Add(index, DateTime.Now.ToString());
                        index++;
                        Thread.Sleep(1000);
                    }
                }
            }
      

  2.   

    to:xiaoqhuang
    按照你的样子加入了lock,但在HsWrite里读取时还是报错误。to:lovefootball 
    在什么地方使用lock?
      

  3.   

    你HsWrite里有加lock吗?
            public void HsWrite()
            {
               lock (hs) {
                 while (true)
                 {
                    IDictionaryEnumerator ie = hs.GetEnumerator();
                    while (ie.MoveNext())
                    {
                        Console.WriteLine("key={0},value={1}", ie.Key, ie.Value);
                        Thread.Sleep(1000);
                    }
                 }
              }
            }
      

  4.   

    to :xiaoqhuang 
    这样会导致部分数据加不到Hashtable里,还有其他的办法吗?
      

  5.   

    http://msdn2.microsoft.com/zh-cn/library/system.collections.hashtable.synchronized(VS.80).aspx
      

  6.   

    to:whycom 
    这个方法试过了,偶尔也会报错误
      

  7.   

    to:whycom   
    这个方法试过了,偶尔也会报错误
    ====
    能保证只有一个线程在写吗?
      

  8.   

    //枚举中不能再写的,这样改就对了。
    using System;
    using System.Collections;
    using System.Threading;
    using System.Collections.Generic;
    using System.Text;namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                test t = new test();
                t.Start();
            }
        }
        public class test
        {
            Hashtable hs = new Hashtable();
            Thread thHsAdd = null;
            Thread thHsWrite = null;
            int index = 0;
            public void Start()
            {
                thHsAdd = new Thread(new ThreadStart(this.HsAdd));
                thHsAdd.Start();
                thHsWrite = new Thread(new ThreadStart(this.HsWrite));
                thHsWrite.Start();
            }
            public void HsAdd()
            {
                while (true)
                {
                    lock (hs)
                    {
                        hs.Add(index, DateTime.Now.ToString());
                    }
                    index++;
                    Thread.Sleep(1000);
                }
            }
            public void HsWrite()
            {
                while (true)
                {
                    lock (hs)
                    {
                        IDictionaryEnumerator ie = hs.GetEnumerator();
                        ie.MoveNext();
                            Console.WriteLine("key={0},value={1}", ie.Key, ie.Value);
                    }
                    Thread.Sleep(1000);
                }
            }
        }
    }
      

  9.   

    感谢大家,问题解决了,原理是在读取HASTABLE时不要直接读取它,而是读取它的一个副本,经过多次测试没有报错,呵呵
    using System;
    using System.Collections;
    using System.Threading;
    using System.Collections.Generic;
    using System.Text;namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                test t = new test();
                t.Start();
            }
        }
        public class test
        {
            Hashtable hs = new Hashtable();
            Thread thHsAdd = null;
            Thread thHsWrite = null;
            Thread thHsDel = null;
            int index = 0;
            public void Start()
            {
                thHsAdd = new Thread(new ThreadStart(this.HsAdd));
                thHsAdd.Start();
                thHsWrite = new Thread(new ThreadStart(this.HsWrite));
                thHsWrite.Start();
                thHsDel = new Thread(new ThreadStart(this.HsDel));
                thHsDel.Start();
            }
            public void HsAdd()
            {                while (true)
                    {
                        lock (hs.SyncRoot)
                        {
                            hs.Add(index, DateTime.Now.ToString());
                        }
                        index++;
                        Thread.Sleep(10);
                    }
            }
            public void HsWrite()
            {
                Hashtable tp = null;
                while (true)
                {
                    tp = (Hashtable)hs.Clone();
                    IDictionaryEnumerator ie = tp.GetEnumerator();
                    while (ie.MoveNext())
                    {
                        Console.WriteLine("key={0},value={1}", ie.Key, ie.Value);
                        Thread.Sleep(100);
                    }
                }
            }
            public void HsDel()
            {
                Hashtable tp = null;
                while (true)
                {
                    tp = (Hashtable)hs.Clone();
                    IDictionaryEnumerator ie = tp.GetEnumerator();
                    while (ie.MoveNext())
                    {
                        if (ie.Key.ToString().IndexOf("0") > -1)
                        {
                            lock (hs.SyncRoot)
                            {
                                hs.Remove(ie.Key);
                            }
                            Console.WriteLine("--------------------------------已删除对象{0}------------------------------" ,ie.Key);
                        }
                       Thread.Sleep(10); //必须加,有效降低CPU占有率
                    }
                }
            }
        }
    }
      

  10.   

    还有你用枚举方式读取hashtable 会有问题,因为读的过程中 写入数据会破坏hashtalbe枚举机制
    给你改了一下程序using System;
    using System.Collections;
    using System.Threading;
    using System.Collections.Generic;
    using System.Text;namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                test t = new test();
                t.Start();
            }
        }
        public class test
        {
            Hashtable hs;
            Hashtable hsSync;
            public test()
            {
                hs = new Hashtable();
                hsSync = Hashtable.Synchronized(hs);
            }
            
            Thread thHsAdd = null;
            Thread thHsWrite = null;
            int index = 0;
            public void Start()
            {
                thHsAdd = new Thread(new ThreadStart(this.HsAdd));
                thHsAdd.Start();
                thHsWrite = new Thread(new ThreadStart(this.HsWrite));
                thHsWrite.Start();
            }
            public void HsAdd()
            {
                while (true)
                {
                    lock (hsSync)
                    {
                        hsSync.Add(index, DateTime.Now.ToString());
                        index++;
                        Thread.Sleep(1000);
                    }
                }
            }
            public void HsWrite()
            {
                while (true)
                {
                    int nCount = hsSync.Keys.Count;
                    for (int i = 0; i < nCount; i++) 
                    {
                        Console.WriteLine( i.ToString() + hsSync[i].ToString());
                    }
                    Console.WriteLine("------------------------------------");
                }
            }
        }
    }
      

  11.   

            public void HsWrite()
            {
                Hashtable tp = null;
                while (true)
                {
                    tp = (Hashtable)hs.Clone();
                    IDictionaryEnumerator ie = tp.GetEnumerator();
                    while (ie.MoveNext())
                    {
                        Console.WriteLine("key={0},value={1}", ie.Key, ie.Value);
                        Thread.Sleep(100);
                    }
                }
            }
    注意检查一下这段代码,可能使你的程序:  每次读hashtable时间间隔越来越长(100*hashtable成员个数 ms),这样写的程序结果是很奇怪和不可控的。
      

  12.   

    用信号量控制肯定没有问题
    using System;
    using System.Collections;
    using System.Threading;
    using System.Collections.Generic;
    using System.Text;namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                test t = new test();
                t.Start();
            }
        }
        
        public class test
        {
            System.Threading.ManualResetEvent obj = new ManualResetEvent(false);
            Hashtable hs = new Hashtable();
            Thread thHsAdd = null;
            Thread thHsWrite = null;
            int index = 0;
            public void Start()
            {
                thHsAdd = new Thread(new ThreadStart(this.HsAdd));
                thHsAdd.Start();
                thHsWrite = new Thread(new ThreadStart(this.HsWrite));
                thHsWrite.Start();
            }
            public void HsAdd()
            {            while (true)
                {
                    if (obj.WaitOne(10, false) == true)
                    {
                        hs.Add(index, DateTime.Now.ToString());
                        index++;
                    }
                    Thread.Sleep(1000);
                }
            }
            public void HsWrite()
            {
                while (true)
                {
                    obj.Reset();
                    IDictionaryEnumerator ie = hs.GetEnumerator();
                    while (ie.MoveNext())
                    {
                        Console.WriteLine("key={0},value={1}", ie.Key, ie.Value);
                        
                    }
                    obj.Set();
                    Thread.Sleep(1000);
                }
            }
        }
    }
      

  13.   

    非常感谢你的新方法,我测试过了,上面的代码偶而也会出错,如果同时不只俩个线程来访问hastable的话,这可方法也会报错,比如:using System;
    using System.Collections;
    using System.Threading;
    using System.Collections.Generic;
    using System.Text;namespace ConsoleApplication1
    {
        class Program1
        {
            static void Main(string[] args)
            {
                test1 t = new test1();
                t.Start();
            }
        }    public class test1
        {
            System.Threading.ManualResetEvent obj = new ManualResetEvent(false);
            Hashtable hs = new Hashtable();
            Thread thHsAdd = null;
            Thread thHsWrite = null;
            Thread thHsDel = null;
            int index = 0;
            public void Start()
            {
                thHsAdd = new Thread(new ThreadStart(this.HsAdd));
                thHsAdd.Start();
                thHsWrite = new Thread(new ThreadStart(this.HsWrite));
                thHsWrite.Start();
                thHsDel = new Thread(new ThreadStart(this.HsDel));
                thHsDel.Start();
            }
            public void HsAdd()
            {            while (true)
                {
                    if (obj.WaitOne(10,false) == true)
                    {
                        hs.Add(index, DateTime.Now.ToString());
                        index++;
                    }
                    Thread.Sleep(10);
                }
            }
            public void HsWrite()
            {
                while (true)
                {
                    obj.Reset();
                    IDictionaryEnumerator ie = hs.GetEnumerator();
                    while (ie.MoveNext())
                    {
                        Console.WriteLine("key={0},value={1}", ie.Key, ie.Value);
                    }
                    obj.Set();
                    Thread.Sleep(10);
                }
            }
            public void HsDel()
            {
                while (true)
                {
                    obj.Reset();
                    IDictionaryEnumerator ie = hs.GetEnumerator();
                    while (ie.MoveNext())
                    {
                        if (ie.Key.ToString().IndexOf("0") > -1)
                        {
                            //lock (hs)
                            //{
                            //    hs.Remove(ie.Key);
                            //}
                            Console.WriteLine("--------------------------------已删除对象{0}------------------------------", ie.Key);
                        }
                    }
                    obj.Set();
                    Thread.Sleep(10);
                }
            }
        }
    }