c # efficient thread-safe queue ConcurrentQueue

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/u011966339/article/details/89916510

The team (EnQueue), a team (TryDequeue), is empty (IsEmpty), to obtain the number of elements in the queue (Count).

A, ConcurrentQueue internal structure:

wps_clip_image-30166

1. The principle

As we all know, in general, non-thread-safe queue implemented in two ways:

1. Use a circular queue array implementation.

2. Use the queue list to achieve.

Take a look at the pros and cons of two ways:

     .Net Farmework realization of ordinary queue Queue uses the first embodiment, when disadvantage is queue space will be insufficient expansion, expansion is achieved mainly open 2 times the original length a new array, and then copy the original data array inside into a new array, when the expansion will have no small memory overhead and performance impact can not be discounted in concurrent environment. Of course, when a constructor is called Queue space may specify the default size, but the amount of data is generally unpredictable, large selection of wasted space will be adhered to, choose a small overhead will copy the memory, and after the required expansion queue display call TrimToSize () method to reclaim unused memory space out.

     When the second linked list implementation Although the elimination of wasted space problem but it increases the pressure on the GC, when the team will be assigned a new node, the node to be discarded when the team, for a large number of the operating team into the team the implementation performance is not high.

    Based on the above two implementations, in case of supporting multi-threading and concurrently issued team enqueued, ConcurrentQueue uses the concept of fragmentation (as indicated above), when ConcurrentQueue allocates memory segment (Segment) is a unit of a segment internal contains a pointer to the next default length is performed and an array 32 of a segment, and has a Head and Tail pointer point to the beginning and the end of segment (a bit like the structure of the operating system memory management and the page segment memory of formula management strategy). TrimToSize call () This method allocates memory implementations not only to reduce the pressure of the GC and do not display the caller's memory recovery (when a certain memory is empty, the segment will be recovered by the memory GC).

2.Segment (para) an internal structure

In fact, for the operation ConcurrentQueue is actually operating on Segment (segment) of.

Segment data structure may be abstracted as follows:

wps_clip_image-5493

Segment Internal main methods:

wps_clip_image-6121

    Internal Segment and implement an array of fairly ordinary queue, but for the team and the operations team used an atomic operation to prevent multithreading competition, random concessions and other technology to ensure the live lock and other issues, and mechanisms to achieve little difference ConcurrentStack, with implementation details and more TryAppend comments in the source code has been set out very clearly on the interpretation, but more to do here.

Second, the enqueue operation

wps_clip_image-24139

As shown above, the dequeue operation is carried out in the tail section, when the failure data into the segment will carry out a rollback operation then continues until a successful attempt, the reason (tail.Append (item) return false failure where ) is the only one when the space within the segment is not being assigned a new segment, will enter the period of time during which an element will fail.

Third, the operation team

wps_clip_image-3291

As shown above, when a team fails to return false rather than the team rollback as a team because of the failure of only one element it is when all the segments in the queue is empty, so the design team became the return bool function values.

Four, it is determined whether the air (the IsEmpty)

  Analyzing the whole is O (1) complexity mainly in three ways:

1. The head node (segment) is not empty return false

2. The head node is empty and the next node returns a true null

3. judged again head node is empty and the next node is not null returns false, this case is described expansion queue, the optional wait to complete expansion

Five, the number of the acquired queue element (the Count)

wps_clip_image-31544

     High position to find the position of low head node and tail node due to the index of the current record of each segment in the segment queue, it is easy to determine the number of elements in the entire cohort.

     Like Microsoft with ConcurrentStack official documents and comments also shows that: to determine whether the queue is empty to use the IsEmpty property rather than judgment Count == 0 because GetHeadTailPositions find the location of the head and tail node in the process large amounts of data into the team and the team is relatively time-consuming operation to determine the position of the head and tail nodes continuous cycle, it is determined whether the queue is empty or used IsEmpty property.

Guess you like

Origin blog.csdn.net/u011966339/article/details/89916510