Lock-free并发Stack的数组实现

 

关于lock-free技术和并发数据结构可以参考花开花落的大作,其中给出了一个基于链表实现的lock-free并发Stack,本文研究lock-free并发stack的数组实现。

在非并发Stack的实现上,一般认为,利用数组要比链表节省时间,同时浪费空间。然而,笔者认为,在并发Stack中,数组在时间上的优势可能不复存在。原因是:

  • 链表实现中,效率瓶颈在top节点指针,必须通过CAS原语对该指针进行锁定。
  • 数组实现中,效率瓶颈除了top节点索引外,还要考虑Stack扩容时数组复制带来的冲突。

在笔者的实现方案中(代码如下所示),凡是判断当前Stack已满的线程都要进行数组扩容复制,,最终利用CAS原语只有一组扩容结果会被更新到原Stack上,这就需要保证从开始进行扩容复制到更新原Stack这段时间,不发生任何其他对原Stack的更新,否则就会产生更新丢失。因此,有必要保证从扩容复制到原Stack更新操作的整个过程是原子操作。这将花费不小的代价。

 

代码如下:

  1using System;
  2using System.Threading;
  3using System.Collections;
  4using System.Collections.Generic;
  5
  6namespace UCMore
  7{
  8    /// <summary>
  9    /// Concurrency Stack for multi-thread enviroment.
 10    /// </summary>
 11    /// <typeparam name="T">Specifices the type of elements in the <see cref="UCMStack"/>.</typeparam>

 12    public class UCMStack<T> : IEnumerable
 13    {
 14        private T[] array;
 15        private int top = -1;
 16        private int capacity = 0;
 17        private int defaultCapacity = 2;
 18
 19        /// <summary>
 20        /// Intializes a <see cref="UCMStack"/> instance.
 21        /// </summary>

 22        public UCMStack()
 23        {
 24        }

 25
 26
 27        /// <summary>
 28        /// Initializes a <see cref="UCMStack"/> instance, specifing a initial capacity for it.
 29        /// </summary>
 30        /// <param name="initialCapacity">The initial capacity.</param>

 31        public UCMStack(int initialCapacity)
 32        {
 33            if (initialCapacity < 0)
 34            {
 35                throw new ArgumentOutOfRangeException("Capacity cannot be negative.");
 36            }

 37            array = new T[initialCapacity];
 38
 39            capacity = initialCapacity;
 40        }

 41
 42        /// <summary>
 43        /// Determints whether the <see cref="UCMStack"/> is empty.
 44        /// </summary>
 45        /// <returns> True represents the <see cref="UCMStack"/> is empty, while 
 46        /// false represents it is not empty.</returns>

 47        public bool IsEmpty()
 48        {
 49            return top == -1;
 50        }

 51
 52        /// <summary>
 53        /// Gets the number of elements contained in the <see cref="UCMStack"/>.
 54        /// </summary>

 55        public int Count
 56        {
 57            get 
 58            
 59                return top + 1
 60            }

 61        }

 62
 63        //TODO: Lock-free UCMStack<T>.Push
 64        /// <summary>
 65        /// Inserts an object at the top of the <see cref="UCMStack"/>.
 66        /// </summary>
 67        /// <param name="item">An object to be instered.</param>

 68        public void Push(T item)
 69        {
 70            int oldCapacity;
 71            int oldTop;
 72
 73            if (this.Count == (oldCapacity = capacity))
 74            {
 75                //oldCapcaity = capacity;
 76                T[] newArray = new T[this.Count == 0 ? defaultCapacity : oldCapacity * 2];
 77                if (this.Count != 0) Array.Copy(array, newArray, this.Count);
 78
 79                if(Interlocked.CompareExchange(
 80                        ref capacity,
 81                        this.Count == 0 ? defaultCapacity : capacity * 2,
 82                        oldCapacity) == oldCapacity)
 83                {
 84                    array = newArray;
 85                }

 86            }

 87
 88            do
 89            {
 90                oldTop = top;
 91            }

 92            while (Interlocked.CompareExchange(ref top, oldTop + 1, oldTop) != oldTop);
 93
 94            array[oldTop + 1= item;
 95        }

 96
 97        //TODO: Test UCMStack<T>.Pop
 98        /// <summary>
 99        /// Removes and returns the object at the top of the <see cref="UCMStack"/>.
100        /// </summary>
101        /// <exception cref="InvalidOperationException">Thrown if the <see cref="UCMStack"/> is empty.</exception>
102        /// <returns>The object at the top of the <see cref="UCMStack"/>.</returns>

103        public T Pop()
104        {
105            int oldTop;
106            T popped;
107
108            if (this.IsEmpty())
109            {
110                throw new InvalidOperationException("The Stack is empty.");
111            }

112            
113            do
114            {
115                oldTop = top;
116                popped = array[top];
117            }

118            while (Interlocked.CompareExchange(ref top, oldTop - 1, oldTop) != oldTop);
119            
120            array[oldTop] = default(T);
121
122            return popped; 
123        }

124
125        /// <summary>
126        /// Returns the object at the top of the <see cref="UCMStack"/>, but don't Removes it. 
127        /// </summary>
128        /// <exception cref="InvalidOperationException">Thrown if the <see cref="UCMStack"/> is empty.</exception>
129        /// <returns>The object at the top of the <see cref="UCMStack"/>.</returns>

130        public T Peek()
131        {
132            if (this.IsEmpty())
133            {
134                throw new InvalidOperationException("The Stack is empty.");
135            }

136
137            return array[top];
138        }

139
140        /// <summary>
141        /// Removes all the elements from the <see cref="UCMStack"/>.
142        /// </summary>

143        public void Clear()
144        {
145            int oldTop;
146            while (top >= 0)
147            {
148                do
149                {
150                    oldTop = top;
151                }

152                while (Interlocked.CompareExchange(ref top, oldTop - 1, oldTop) != oldTop);
153
154                array[oldTop] = default(T);
155            }

156        }

157
158        IEnumerable Members
173    }

174}

 

posted on 2009-04-21 21:03  dongzi  阅读(596)  评论(0)    收藏  举报

导航