forked from sshnet/SSH.NET
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLinkedListQueue.cs
More file actions
143 lines (126 loc) · 4.5 KB
/
LinkedListQueue.cs
File metadata and controls
143 lines (126 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Threading;
namespace Renci.SshNet.Common
{
/// <summary>
/// Fast concurrent generic linked list queue.
/// </summary>
internal class LinkedListQueue<T> : IDisposable
{
sealed class Entry<E>
{
public E Item;
public Entry<E> Next;
}
private readonly object _lock = new object();
private Entry<T> _first;
private Entry<T> _last;
private bool _isAddingCompleted;
/// <summary>
/// Gets whether this <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/> has been marked as complete for adding and is empty.
/// </summary>
/// <value>Whether this queue has been marked as complete for adding and is empty.</value>
public bool IsCompleted
{
get { return _isAddingCompleted && _first == null && _last == null; }
}
/// <summary>
/// Gets whether this <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/> has been marked as complete for adding.
/// </summary>
/// <value>Whether this queue has been marked as complete for adding.</value>
public bool IsAddingCompleted
{
get { return _isAddingCompleted; }
set
{
lock (_lock)
{
_isAddingCompleted = value;
}
}
}
/// <summary>
/// Adds the item to <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/>.
/// </summary>
/// <param name="item">The item to be added to the queue. The value can be a null reference.</param>
public void Add(T item)
{
lock (_lock)
{
if (_isAddingCompleted)
{
return;
}
var entry = new Entry<T>()
{
Item = item
};
if (_last != null)
{
_last.Next = entry;
}
_last = entry;
_first ??= entry;
Monitor.PulseAll(_lock);
}
}
/// <summary>
/// Marks the <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/> instances as not accepting any more additions.
/// </summary>
public void CompleteAdding()
{
lock (_lock)
{
IsAddingCompleted = true;
Monitor.PulseAll(_lock);
}
}
/// <summary>
/// Tries to remove an item from the <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/>.
/// </summary>
/// <returns><c>true</c>, if an item could be removed; otherwise <c>false</c>.</returns>
/// <param name="item">The item to be removed from the queue.</param>
/// <param name="wait">Wait for data or fail immediately if empty.</param>
public bool TryTake(out T item, bool wait)
{
lock (_lock)
{
if (_first == null && !wait)
{
item = default;
return false;
}
while (_first == null && !_isAddingCompleted)
{
_ = Monitor.Wait(_lock);
}
if (_first == null && _isAddingCompleted)
{
item = default;
return false;
}
item = _first.Item;
_first = _first.Next;
return true;
}
}
/// <summary>
/// Releases all resource used by the <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/> object.
/// </summary>
/// <remarks>Call <see cref="Dispose"/> when you are finished using the
/// <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/>. The <see cref="Dispose"/> method leaves the
/// <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/> in an unusable state. After calling
/// <see cref="Dispose"/>, you must release all references to the
/// <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/> so the garbage collector can reclaim the memory that
/// the <see cref="T:Renci.SshNet.Common.LinkedListQueue`1"/> was occupying.</remarks>
public void Dispose()
{
lock (_lock)
{
_first = null;
_last = null;
_isAddingCompleted = true;
}
}
}
}