線程鎖

使用線程鎖的體會:

多線程的使用已經很普及,但是在使用多線程時,一定要注意安全,比如:多個線程能夠同時訪問同一個變量時,要注意這個共同變量的資源分配策略。

通常情況下是爲其【加鎖】,加鎖也即創建臨界區,也就是當一個線程訪問一段代碼時,將這段代碼進行鎖定。但,實際理解起來並不是很簡單,創建臨界區在C#中使用lock關鍵字來鎖定一段代碼。

如:lock(object){操作....實際要控制併發線程要訪問的公共變量}

要想真正實現代碼段加鎖,如上代碼的object對象很重要,對於object的定義規則:

  • object必須是引用類型,但還不能是string,因爲系統給string的分配比較特殊;
  • 其次,這個object對象必須是 多個線程同時能夠識別或可見的,這樣才能起到作用;
  • 還有,object的定義最好是private私有的,如果是public型,別的代碼對其訪問時,同時某個線程正在鎖定,就會造成等待;
  • 最後,這個object其實是一個輔助變量,唯一的意義就是lock(object),對於object不要用作他用。

其原理很簡單,就是lock住多個線程共同識別的對象,當其他線程訪問某段代碼段時發現這個object被鎖定,就必須排隊等待,直到這個object被釋放,真正起到鎖定代碼段的關鍵是這個object對象,不是其他。

如果定義了多個臨界區,但是這些臨界區使用的是同一個【鎖定實例對象】也即上述的object,那麼當某線程訪問一個臨界區時,其他臨界區也將被鎖定,不能被其他線程訪問。

注意

臨界區內本身就是爲多個線程同時訪問的,因此請不要在臨界區內加入UI線程的東西,如控件的使用,否則可能造成死鎖。

例子:

private StringBuilder _cache = new StringBuilder();//緩存,多線程爭奪訪問的資源
        private object _objectLock = new object();//鎖對象

        void Enqueue(string val)//入隊
        {
            #region 代碼段1

            lock (_objectLock)
            {
                _cache.Append(val);
            }

            #endregion
        }

        string Dequeue()//出隊
        {
            #region 代碼段2

            lock (_objectLock)
            {
                int idx = _cache.ToString().IndexOf('\n');
                if (idx >= 0)
                {
                    string sub = _cache.ToString().Substring(0, idx + 1);
                    _cache.Remove(0, idx + 1);
                    return sub;
                }
                return null;
            }

            #endregion
        }

以上代碼有兩個臨界區,代碼段1和代碼段2,當一個線程訪問代碼段1時,肯定代碼段1被鎖定,其他線程是不允許訪問代碼段1的,同時其他線程也是不能訪問代碼段2的,因爲兩個代碼段使用的是一個鎖對象_objectLock

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章