我现在要多线程方式访问一个全局的值,这个值必需是全局唯一的。(假设是 int类型)
从0开始以1步进递增。就是说,不管哪个线程进来,得到的这个值,都别跟别的线程得到的不一样。

解决方案 »

  1.   

    线程同步...最简单的就是用lock加锁...去看MSDN...线程同步(C# 编程指南)
      

  2.   


    加了锁,别的线程进来,如果是一个Asp.Net程序的一个客户端请求呢?我怎么回应,或者设置线程等待?
      

  3.   

    我解释一下,Interlocked类的方法都是原子操作,和普通的lock等锁机制相比,Interlocked是锁定内存总线,保证了过程的完整性。不是先赋值,再计算,再赋值。效率比lock提高2倍左右。
      

  4.   

    你那个整数的操作只是简单地加一,lock又不会耗费很长时间,基本上客户端请求应答没什么影响。
      

  5.   


    我刚试了,这个好像可以;但如果我要获取的值不是int类型呢?可能是字母组合A~Z{n}
      

  6.   

    那你的字母组合生成的规律是什么?如果没有规律,用lock就行了,我也是做东西做的神经了,习惯性的避免lock,其实在绝大部分程序中,lock和interlocked的差别根本不会带来任何影响。
      

  7.   


    我只是举个例子嘛,要真是的话,我全一个全局静态的变量就行了,反正加一下也不花多长时间;我的意思是说“如果这个值生成的过程需要一定的时间,比如10秒种,而在上一个线程进行的时候,另一个线程进来了,我怎么让它等会儿?如果这个线程是Asp.net Request产生的,这个时候,我该怎么回应这个请求呢?还是不用回应?直接让线程等待就行了?”
      

  8.   

    你最后这个问题实际是个复杂的问题了,如果一个过程在一秒以上,那么lock整个过程肯定是思路上有问题了,要分析这个过程中哪些变量会有线程同步问题,然后分步lock。具体问题具体分析。
      

  9.   


    我其实是想找一个比较完善的解决办法的,既然这样,那我说实际的吧。需求:我现在要生成一个编号这个编号的格式是“特定的Id号_年月日_一个全局唯一的编号”,这个编号要每天0点0分0时0秒初始化成0,并且,同一天里,不同特定Id号等到的全局唯一编号不能相同。这个编号的请求,是Asp.Net页面完成的。这个页面的访问量可能在同一时间产生很多个申请这个编号的进程。
    初始化的问题,我可以用SqlServer的定时“事务”来解决。就是将这个值存到一个表的字段里,每天定时设置成0。其实这样也不保险,如果那个时间正好有客户请求呢?但我目前也只想到这个办法。另外一个重点问题,如果一个访问者的请求还没有完成,其它N个访问者的请求就已经来了,这个时候我怎么办呢?
      

  10.   

    你没去看那个链接吗...如果同步对象很复杂可以用同步事件AutoResetEvent或ManualResetEvent...但是Web请求是无连接的,等待时间太长会导致超时...你可以用Ajax异步请求或者先理清楚逻辑改变操作,尽量不要用同步模式...
      

  11.   

    先说第一个,实际interlocked是可以的,字符串加上那个被原子操作的整数就行了。当然用Lock也绝对没问题,这个过程并不耗时。
    第二个,如果一个访问者的请求还没有完成,其它的进来了,会等待,直到锁被释放后进去一个,其余的继续等待,直到全部完成,这是正常的,你什么都不用做。
      

  12.   

    先感谢各位的指导!
    先发上我的解决办法,如果有问题请回帖指出来,三天后结帖:    /// <summary>
        /// 稿件编号驱动工厂
        /// <para>稳定</para>
        /// </summary>
        public static class NumberProviderFactory
        {
            /// <summary>
            /// 全局稿件编号驱动
            /// </summary>
            private static INumberProvider GlobalNumberProvider;        /// <summary>
            /// 获取一个INumberProvider实例
            /// <para>单例模式,全局唯一</para>
            /// </summary>
            /// <param name="configFilePath">文档配置文件路径</param>
            /// <returns></returns>
            public static INumberProvider GetNumberProvider(string configFilePath)
            {
                if (GlobalNumberProvider == null)
                {
                    GlobalNumberProvider = new NumberProvider(configFilePath);
                }
                return GlobalNumberProvider;
            }
        }    /// <summary>
        /// 稿件编号驱动接口
        /// </summary>
        public interface INumberProvider
        {
            /// <summary>
            /// 访问线程计数器
            /// </summary>
            int VisitorCounter { get; }        /// <summary>
            /// 获取当前串号
            /// </summary>
            /// <returns></returns>
            int GetCurrent();        /// <summary>
            /// 重置当前串号为0
            /// </summary>
            void Reset();
        }    /// <summary>
        /// 稿件编号驱动
        /// </summary>
        public class NumberProvider : INumberProvider
        {
            /// <summary>
            /// xml配置文件的路径
            /// </summary>
            private string xmlPath = string.Empty;        /// <summary>
            /// 单线程排它锁
            /// </summary>
            private Mutex AppLocker = new Mutex();        private int _VisitorCounter;
            /// <summary>
            /// 访问线程计数器
            /// </summary>
            public int VisitorCounter
            {
                get { return this._VisitorCounter; }
            }        #region private int CurrentNumber { get; set; }
            /// <summary>
            /// 获取或设置当前串号
            /// </summary>
            private int CurrentNumber
            {
                get 
                {
                    try
                    {
                        XmlDocument xd = new XmlDocument();
                        xd.Load(xmlPath);
                        XmlNode xn = xd.SelectSingleNode("/document/numberseed/value");
                        if (xn != null)
                            return int.Parse(xn.InnerText);
                        return 0;
                    }
                    catch
                    {
                        return -1;
                    }
                }
                set
                {
                    try
                    {
                        XmlDocument xd = new XmlDocument();
                        xd.Load(xmlPath);                    XmlNode xn = xd.SelectSingleNode("/document/numberseed/value");
                        if (xn != null)
                            xn.InnerText = value.ToString();                    xd.Save(xmlPath);
                    }
                    catch { }
                }
            }
            #endregion        /// <summary>
            /// 使用当前应用程序指定的配置文件计数
            /// </summary>
            /// <param name="configFilePath">文档配置文件路径</param>
            public NumberProvider(string configFilePath)
            {
                if (string.IsNullOrEmpty(configFilePath))
                    this.xmlPath = HttpRuntime.AppDomainAppPath + "documentconf.xml";
                else
                    this.xmlPath = configFilePath;            this._VisitorCounter = 0;
            }        #region public virtual int GetCurrent()
            /// <summary>
            /// 获取当前串号
            /// </summary>
            /// <returns></returns>
            public virtual int GetCurrent()
            {
                this._VisitorCounter++;
                AppLocker.WaitOne();            try
                {
                    CurrentNumber++;
                    return CurrentNumber;
                }
                finally
                {
                    AppLocker.ReleaseMutex();
                    this._VisitorCounter--;
                }
            }
            #endregion        #region public virtual void Reset()
            /// <summary>
            /// 重置当前串号为0,并更新统计日期
            /// </summary>
            public virtual void Reset()
            {
                this._VisitorCounter++;
                AppLocker.WaitOne();            try
                {
                    CurrentNumber = 0;
                    XmlDocument xd = new XmlDocument();
                    xd.Load(xmlPath);
                    XmlNode xn = xd.SelectSingleNode("/document/numberseed/date");
                    if (xn != null)
                        xn.InnerText = DateTime.Now.Date.ToString("yyyy-MM-dd");
                    xd.Save(xmlPath);
                }
                finally
                {
                    AppLocker.ReleaseMutex();
                    this._VisitorCounter--;
                }
            }
            #endregion
        }    public class Global : System.Web.HttpApplication
        {
            /// <summary>
            /// 稿件编号控制器
            /// </summary>
            Timer NumberControler;        /// <summary>
            /// 控制器同步句柄
            /// </summary>
            AutoResetEvent NumberContorlerHandle = new AutoResetEvent(false);        protected void Application_Start(object sender, EventArgs e)
            {
                DateTime nextDayStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.AddDays(1).Day, 0, 0, 0);            //当前与下一天开始时间的时间差
                TimeSpan diff = nextDayStart - DateTime.Now;            TimerCallback tc = new TimerCallback(ResetNumberCount);
                NumberControler = new Timer(tc, NumberContorlerHandle, diff, new TimeSpan(24, 0, 0));
            }        /// <summary>
            /// 初始化稿件编号
            /// </summary>
            /// <param name="o"></param>
            protected void ResetNumberCount(object o)
            {
                AutoResetEvent are = (AutoResetEvent)o;
                NumberProviderFactory.GetNumberProvider(HttpRuntime.AppDomainAppPath + "documentconf.xml").Reset();
                are.Set();
            }
        }