关于线程间同步的问题,紧急求助!我有一个类,主要是操作一个List<T>.
这个类有若干个方法:
比如向List中插入:ADD();
从List中删除:Remove();
枚举List中的数据:GetByXX1();GetByXX2();GetByXX3();而这些方法都可以是被多线程并发执行的。
因为List不是线程安全的。
所以加锁是避免不了的了。
但是如果每个方法都加了锁,那就全变成同步执行的了。我希望插入删除这些操作同步,而读取操作并行。
应该怎么做呢?项目最后一天,大家帮忙!

解决方案 »

  1.   

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;namespace WindowsApplication78
    {
        public partial class Form1 : Form
        {
            int i = 0;
            List<String> L = new List<string>();
            ListBox LB1 = new ListBox();
            ListBox LB2 = new ListBox();        public Form1()
            {
                InitializeComponent();            LB1.Parent = this;            LB2.Parent = this;
                LB2.Location = new Point(150, 0);            this.Shown += new EventHandler(Form1_Shown);
            }        void Form1_Shown(object sender, EventArgs e)
            {
                Thread T = new Thread(new ThreadStart(Write));
                T.IsBackground = true;
                T.Start();
                T = new Thread(new ThreadStart(Read1));
                T.IsBackground = true;
                T.Start();
                T = new Thread(new ThreadStart(Read2));
                T.IsBackground = true;
                T.Start();
            }        void Write()
            {
                try
                {
                    while (true)
                        if (Monitor.TryEnter(L))
                        {
                            L.Add(i++.ToString());
                            Monitor.Exit(L);
                            Thread.Sleep(100);
                        }
                }
                catch
                {
                    // 忽略程序退出的异常
                }
            }        delegate void ReadToListBox(String S);        void Read1()
            {
                try
                {
                    while (true)
                        if (Monitor.TryEnter(L))
                        {
                            if (L.Count > 0)
                            {
                                String S = L[L.Count - 1];
                                L.RemoveAt(L.Count - 1);
                                this.Invoke(new ReadToListBox(DoReadToListBox1), new Object[] { S });
                            }
                            Monitor.Exit(L);
                        }
                }
                catch
                {
                    // 忽略程序退出的异常
                }
            }        void Read2()
            {
                try
                {
                    while (true)
                        if (Monitor.TryEnter(L))
                        {
                            if (L.Count > 0)
                            {
                                String S = L[L.Count - 1];
                                L.RemoveAt(L.Count - 1);
                                this.Invoke(new ReadToListBox(DoReadToListBox2), new Object[] { S });
                            }
                            Monitor.Exit(L);
                        }
                }
                catch
                {
                    // 忽略程序退出的异常
                }
            }        void DoReadToListBox1(String S)
            {
                LB1.Items.Add(S);
                LB1.SelectedIndex = LB1.Items.Count - 1;
                LB1.Invalidate();
            }        void DoReadToListBox2(String S)
            {
                LB2.Items.Add(S);
                LB2.SelectedIndex = LB2.Items.Count - 1;
                LB2.Invalidate();
            }
        }
    }
      

  2.   

    谢谢楼上的例子。
    有点不明白请教一下!1.如果把Monitor.TryEnter(L) 改成
    Monitor.Enter(L) 并且把while (true)
    去掉,效果是不是一样的?2.你的代码里,Read1 和 Read2 是不是同步的?
    也就是说Read1获得了锁,Read2必须等待?
      

  3.   

    如果读取量很大,并且写入量小的多的情况下,可以使用读写锁
    但是读写锁本身的效率不如Monitor,所以如果写入量也不小的话,效率反而会比较低
      

  4.   

    1.在这个例子里可以替换成Monitor.Enter,不过while怎么能去掉,去掉线程就结束了,
    如果你只是想读一次,然后退出线程,那是可以不用while,然后用Monitor.Enter等待获得锁,然后读一次就结束了2.read1进入moniter.tryenter开始的互斥区后,read2就是等待,直到read1的moniter.exit释放互斥锁
    互斥是针对共享的资源,比如这里的list,某一时间只有一个线程能访问,其他要等待,同步针对是线程间,比如这里要先写入,有数据后才能读出来
    这里你如果读不用锁,那执行的流程就是不可预知的,就不是原子操作read1执行完
    String S = L[L.Count - 1];
    L.RemoveAt(L.Count - 1);
    时间片轮到read2了,
    read2这时刚好接上次执行到
    String S = L[L.Count - 1];
    接下来执行
    L.RemoveAt(L.Count - 1);
    了一下,那就是删2次了,那数据要么就丢失,要么就是L.Count - 1=-1超出索引
      

  5.   

    读写锁要慎用并发数据结构 : .NET Framework 中提供的读写锁 
    http://www.cnblogs.com/lucifer1982/archive/2008/12/07/1349437.html
      

  6.   

    真的非常感谢你,
    ReaderWriterLockSlim 正式解决我的问题的方法。