Menu

[r3189]: / trunk / Src / Notifications.UQueue.pas  Maximize  Restore  History

Download this file

179 lines (144 with data), 4.8 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
{
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/
*
* Copyright (C) 2013, Peter Johnson (www.delphidabbler.com).
*
* $Rev$
* $Date$
*
* Defines a class that manages a thread safe queue of notifications that are
* awaiting display.
}
unit Notifications.UQueue;
interface
uses
// Delphi
SyncObjs, Generics.Collections,
// Project
Notifications.UData;
type
/// <summary>Manages a thread safe queue of notifications that are awaiting
/// display.</summary>
/// <remarks>Notifications can be placed in the queue and removed from it by
/// different threads.</remarks>
TNotificationQueue = class(TObject)
strict private
const
/// <summary>Maximum size of queue.</summary>
MaxQueueSize = 20;
class var
/// <summary>Queue of notifications.</summary>
fQueue: TQueue<TNotificationData>;
/// <summary>Critical section that ensures queue is accessed by only one
/// thread at a time.</summary>
fCriticalSection: TCriticalSection;
/// <summary>Event object that enables threads reading the queue to block
/// while the queue is empty.</summary>
/// <remarks>NOTE: This lock is designed for use with a single reading
/// thread and is not guaranteed to work properly should more than one
/// task block on the empty queue.</remarks>
fEmptyLock: TSimpleEvent;
strict private
/// <summary>Checks if the queue is full.</summary>
function IsFull: Boolean; inline;
/// <summary>Checks if the queue is empty.</summary>
function IsEmpty: Boolean; inline;
public
/// <summary>Creates objects shared amongst all instances.</summary>
class constructor Create;
/// <summary>Frees objects shared amongst all instances.</summary>
class destructor Destroy;
/// <summary>Attempts to add a new notification data item onto the end of
/// the queue.</summary>
/// <param name="Value">TNotificationData [in] Notification data to be
/// added to queue.</param>
/// <returns>Boolean. True if data was added to the queue or False if the
/// queue was full and the data was not added.</returns>
function Push(const Value: TNotificationData): Boolean;
/// <summary>Attempts to read and remove a notification data item from the
/// front of the queue.</summary>
/// <param name="Value">TNotificationData [out] Receives any notification
/// data added to queue.</param>
/// <returns>Boolean. True if data was read from the queue or False if the
/// queue was empty and no data could be read.</returns>
/// <remarks>If False is returned, Value is undefined.</remarks>
function Pop(out Value: TNotificationData): Boolean;
/// <summary>Waits for the empty lock event to enter a singalled state.
/// </summary>
/// <param name="Timeout">Cardinal [in] Maximum amount of time to wait.
/// </param>
/// <returns>TWaitResult. Indicates how the wait operation finished.
/// </returns>
class function WaitForEmptyLock(Timeout: Cardinal): TWaitResult;
/// <summary>Releases any locks on the queue.</summary>
class procedure ReleaseLocks;
end;
implementation
{ TNotificationQueue }
class constructor TNotificationQueue.Create;
begin
fCriticalSection := TCriticalSection.Create;
fQueue := TQueue<TNotificationData>.Create;
fEmptyLock := TSimpleEvent.Create;
fEmptyLock.ResetEvent;
end;
class destructor TNotificationQueue.Destroy;
begin
fEmptyLock.Free;
fQueue.Free;
fCriticalSection.Free;
end;
function TNotificationQueue.IsEmpty: Boolean;
begin
Result := fQueue.Count = 0;
end;
function TNotificationQueue.IsFull: Boolean;
begin
Result := fQueue.Count = MaxQueueSize;
end;
function TNotificationQueue.Pop(out Value: TNotificationData): Boolean;
begin
fCriticalSection.Acquire;
try
Result := not IsEmpty;
if Result then
begin
Value := fQueue.Dequeue;
if IsEmpty then
fEmptyLock.ResetEvent;
end;
finally
fCriticalSection.Release;
end;
end;
function TNotificationQueue.Push(const Value: TNotificationData): Boolean;
var
WasEmpty: Boolean;
begin
fCriticalSection.Acquire;
try
WasEmpty := IsEmpty;
Result := not IsFull;
if Result then
begin
fQueue.Enqueue(Value);
if WasEmpty then
fEmptyLock.SetEvent;
end;
finally
fCriticalSection.Release;
end;
end;
class procedure TNotificationQueue.ReleaseLocks;
begin
// only the one lock!
fEmptyLock.SetEvent;
end;
class function TNotificationQueue.WaitForEmptyLock(Timeout: Cardinal):
TWaitResult;
begin
Result := fEmptyLock.WaitFor(Timeout);
end;
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.