Is it necessary to do Multi-thread protection for a Boolean property in Delphi? - multithreading

I found a Delphi library named EventBus and I think it will be very useful, since the Observer is my favorite design pattern.
In the process of learning its source code, I found a piece of code that may be due to multithreading security considerations, which is in the following (property Active's getter and setter methods).
TSubscription = class(TObject)
private
FActive: Boolean;
procedure SetActive(const Value: Boolean);
function GetActive: Boolean;
// ... other members
public
constructor Create(ASubscriber: TObject;
ASubscriberMethod: TSubscriberMethod);
destructor Destroy; override;
property Active: Boolean read GetActive write SetActive;
// ... other methods
end;
function TSubscription.GetActive: Boolean;
begin
TMonitor.Enter(self);
try
Result := FActive;
finally
TMonitor.exit(self);
end;
end;
procedure TSubscription.SetActive(const Value: Boolean);
begin
TMonitor.Enter(self);
try
FActive := Value;
finally
TMonitor.exit(self);
end;
end;
Could you please tell me the lock protection for FActive is whether or not necessary and why?

Summary
Let me start by making this point as clear as possible: Do not attempt to distill multi-threaded development into a set of "simple" rules. It is essential to understand how the data is shared in order to evaluate which of the available concurrency protection techniques would be correct for a particular situation.
The code you have presented suggests the original authors had only a superficial understanding of multi-threaded development. So it serves as a lesson in what not to do.
First, locking the Boolean for read/write access in that way serves no purpose at all. I.e. each read or write is already atomic.
Furthermore, in cases where the property does need protection for concurrent access: it fails abysmally to provide any protection at all.
The net effect is redundant ineffective code that can trigger pointless wait states.
Thread-safety
In order to evaluate 'thread-safety', the following concepts should be understood:
If 2 threads 'race' for the opportunity to access a shared memory location, one will be first, and the other second. In the absence of other factors, you have no control over which thread would 'start' its access first.
Your only control is to block the 'second' thread from concurrent access if the 'first' thread hasn't finished its critical work.
The word "critical" has loaded meaning and may take some effort to fully understand. Take note of the explanation later about why a Boolean variable might need protection.
Critical work refers to all the processing required for the operation on the shared data to be deemed complete.
It's related to concepts of atomic operations or transactional integrity.
The 'second' thread could either be made to wait for the 'first' thread to finish or to skip its operation altogether.
Note that if the shared memory is accessed concurrently by both threads, then there's the possibility of inconsistent behaviour based on the exact ordering of the internal sub-steps of each thread's processing.
This is the fundamental risk and area of concern when thinking about thread-safety. It is the base principle from which other principles are derived.
'Simple' reads and writes are (usually) atomic
No concurrent operations can interfere with the reading/writing of a single byte of data. You will always either get the value in its entirety or replace the value in its entirety.
This concept extends to multiple bytes up to the machine architecture bit size; but does have a caveat, known as tearing.
When a memory address is not aligned on the bit size, then there's the possibility of the bytes spanning the end of one aligned location into the beginning of the next aligned location.
This means that reading/writing the bytes may take 2 operations at the machine level.
As a result 2 concurrent threads could interleave their sub-steps resulting in invalid/incorrect values being read. E.g.
Suppose one thread writes $ffff over an existing value of $0000 while another reads.
"Valid" reads would return either $0000 or $ffff depending on which thread is 'first'.
If the sub-steps run concurrently, then the reading thread could return invalid values of $ff00 or $00ff.
(Note that some platforms might still guarantee atomicity in this situation, but I don't have the knowledge to comment in detail on this.)
To reiterate: single byte values (including Boolean) cannot span aligned memory locations. So they're not subject to the tearing issue above. And this is why the code in the question that attempts to protect the Boolean is completely pointless.
When protection is needed
Although reads and writes in isolation are atomic, it's important to note that when a value is read and impacts a write decision, then this cannot be assumed to be thread-safe. This is best explained by way of a simple example.
Suppose 2 threads invert a shared boolean value: FBool := not FBool;
2 threads means this happens twice and once both threads have finished, the boolean should end up having its starting value. However, each is a multi-step operation:
Read FBool into a location local to the thread (either stack or register).
Invert the value.
Write the inverted value back to the shared location.
If there's no thread-safety mechanism employed then the sub-steps can run concurrently. And it's possible that both threads:
Read FBool; both getting the starting value.
Both threads invert their local copies.
Both threads write the same inverted value to the shared location.
And the end result is that the value is inverted when it should have been reverted to its starting value.
Basically the critical work is clearly more than simply reading or writing the value. To properly protect the boolean value in this situation, the protection must start before the read, and end after the write.
The important lesson to take away from this is that thread-safety requires understanding how the data is shared. It's not feasible to produce an arbitrary generic safety mechanism without this understanding.
And this is why any such attempt as in the EventBus code in the question is almost certainly doomed to be deficient (or even an outright failure).

Related

Given sufficient memory, are locks unnecessary when there is only a single dedicated writer thread?

For a scenario with multiple reader threads and a single writer thread, where the readers are allowed to read slightly outdated data, I've concocted a lockless control flow as shown below in its most basic form in pseudocode:
GLOBAL_ATOMIC_POINTER shared_pointer
// Only called by the reader threads.
read()
THREAD_LOCAL_POINTER read_pointer := shared_pointer
return read_data_at(read_pointer)
// Only called by the writer thread.
write(input)
THREAD_LOCAL_ARRAY array
THREAD_LOCAL_POINTER write_pointer := shared_pointer
if write_pointer == location_of_last_element(array)
write_pointer := location_of_first_element(array)
else
write_pointer := location_of_next_element(array, write_pointer)
write_data_at(write_pointer, input)
shared_pointer := write_pointer
Let's call MAX_READING_DURATION the maximum period of time that a call to read() can take to complete, and MIN_WRITING_DURATION the minimum period of time that a call to write() can take to complete.
Now, with shared_pointer guaranteed to be atomic, as long as MAX_READING_DURATION < ELEMENT_COUNT(ARRAY) * MIN_WRITING_DURATION, this scheme should be perfectly safe.
Or have I overlooked something? If not, I'm sure this is a well known thing, and I'd like to know the proper terminology is, so I can use that when I explain/advocate this approach to others.
Sufficient memory and the total number of writing threads are not the criteria for determining what can and can't be lockless.
One important feature of lock-free programming is that if you suspend a single thread it will never prevent other threads from making progress through their own lock-free operations.
But, more importantly: The main feature your (single-writer) code needs to adhere to in order to be lock-free is 'sequential consistency':
Sequential Consistency means 'all threads agree on the order in which memory operations occurred, and that order is consistent with the order of operations in the program source code'.
If the code can't guarantee Sequential Consistency it must prevent memory reordering. ( Here is more info on Memory Reordering: http://preshing.com/20120515/memory-reordering-caught-in-the-act/ )
Finally, I'd recommend checking out these resources to dig deeper into lock-free multi-threaded programming concepts:
http://concurrencykit.org/presentations/lockfree_introduction/#/
http://www.drdobbs.com/lock-free-data-structures/184401865
Good luck!

Can I mix and match InterlockedIncrement and CriticalSection?

Previously, I had code like this:
EnterCriticalSection(q^);
Inc(global_stats.currentid);
LeaveCriticalSection(q^);
and I changed it to:
InterlockedIncrement(global_stats.currentid);
and I found out there are some code like this:
EnterCriticalSection(q^);
if (global_stats.currentid >= n) then
begin
LeaveCriticalSection(q^);
Exit;
end;
LeaveCriticalSection(q^);
So, question is , can I mix and match InterLockedIncrement and Enter/Leave CriticalSection?
which has a faster performance? critical and atomic?
Can I mix and match InterLockedIncrement and Enter/Leave CriticalSection?
In general, no you cannot. Critical sections and atomic operations do not interact.
Atomic functions, like your call to InterLockedIncrement, operate completely independently from critical sections and other locks. That is, one thread can hold the lock, and the other thread can at the same time modify the protected variable. Critical sections, like any other form of mutual exclusion, only work if all parties that operate on the shared data, do so when holding the lock.
However, from what we can see of your code, the critical section is needless in this case. You can write the code like this:
// thread A
InterlockedIncrement(global_stats.currentid);
....
// thread B
InterlockedIncrement(global_stats.currentid);
....
// thread C
if global_stats.currentid >= n then
Exit;
That code is semantically equivalent to your previous code with a critical section.
As for which performs better, the original code with the lock, and the code above without, the latter would be expected to perform better. Broadly speaking, lock free code can be expected to be better than code that uses locks, but that's not a rule that can be relied upon. Some algorithms can be faster if implemented with locks than equivalent lock-free implementations.
No, in general you cannot.
Critical section is used to assure that of all protected blocks of code at most one is executing at a given moment. If such protected block accesses currentid and that variable is modified at another place, code may work incorrectly.
In a specific case, it may be OK to mix&match but then you would have to check all affected code and rethink the processing so you'll be sure nothing can go wrong.

Post message from Thread to GUI best practice?

I am working on small monitoring application which will have some threads for communication with some devices via SNMP, TCP, ICMP, other threads have to perform some calculations.
All this result I have to output in GUI (some Forms or TabSheets).
I am thinking about next possibilities:
use Synchronize from every worker thread:
use shared buffer and windows messaging mechanism. Thread will put message in shared buffer (queue) and will notify GUI with windows message.
use separate thread which will listen for Synchronization primitives (Events, Semaphores, etc) and use again Synchronize, but only from GUI-dedicated thread only, or Critical Section on GUI to display message.
UPDATE: (Proposed by one workmate) use shared buffer and TTimer in main form which will check periodically (100-1000 ms) shared buffer and consuming, instead of windows messaging. (Does it have some benefit over messaging?)
Other?
Dear experts, please explain what is the best practice or what are the advantages and disadvantages of exposed alternatives.
UPDATE:
As idea:
//shared buffer + send message variant
LogEvent global function will be called from everywhere (from worker threads too):
procedure LogEvent(S: String);
var
liEvent: IEventMsg;
begin
liEvent := TEventMsg.Create; //Interfaced object
with liEvent do
begin
Severity := llDebug;
EventType := 'General';
Source := 'Application';
Description := S;
end;
MainForm.AddEvent(liEvent); //Invoke main form directly
end;
In Main Form, where Events ListView and shared section (fEventList: TTInterfaceList which is already thread-safe) we'll be:
procedure TMainForm.AddEvent(aEvt: IEventMsg);
begin
fEventList.Add(aEvt);
PostMessage(Self.Handle, WM_EVENT_ADDED, 0, 0);
end;
Message handler:
procedure WMEventAdded(var Message: TMessage); message WM_EVENT_ADDED;
...
procedure TMainForm.WMEventAdded(var Message: TMessage);
var
liEvt: IEventMsg;
ListItem: TListItem;
begin
fEventList.Lock;
try
while fEventList.Count > 0 do
begin
liEvt := IEventMsg(fEventList.First);
fEventList.Delete(0);
with lvEvents do //TListView
begin
ListItem := Items.Add;
ListItem.Caption := SeverityNames[liEvt.Severity];
ListItem.SubItems.Add(DateTimeToStr(now));
ListItem.SubItems.Add(liEvt.EventType);
ListItem.SubItems.Add(liEvt.Source);
ListItem.SubItems.Add(liEvt.Description);
end;
end;
finally
fEventList.UnLock;
end;
end;
Is there something bad? Main Form is allocated ONCE on application startup and Destroyed on application exit.
Use Synchronize from every worker thread
This would probably be the simplest approach to implement, but as others have indicated will lead to your IO threads being blocked. This may/may not be a problem in your particular application.
However it should be noted that there are other reasons to avoid blocking. Blocking can make performance profiling a little trickier because it effectively pushes up the time spent in routines that are "hurrying up and waiting".
Use shared buffer and windows messaging mechanism
This is a good approach with a few special considerations.
If your data is extremely small, PostMessage can pack it all into the parameters of the message making it ideal.
However, since you make mention of a shared buffer, it seems you might have a bit more data. This is where you have to be a little careful. Using a "shared buffer" in the intuitive sense can expose you to race conditions (but I'll cover this in more detail later).
The better approach is to create a message object and pass ownership of the object to the GUI.
Create a new object containing all the details required for the GUI to update.
Pass the reference to this object via the additional parameters in PostMessage.
When the GUI finishes processing the message it is responsible for destroying it.
This neatly avoids the race conditions.
WARNING: You need to be certain the GUI gets all your messages, otherwise you will have memory leaks. You must check the return value of PostMessage to confirm it was actually sent, and you may as well destroy the object if not sent.
This approach works quite well if the data can be sent in light-weight objects.
Use separate thread ...
Using any kind of separate intermediate thread still requires similar considerations for getting the relevant data to the new thread - which then still has to be passed to the GUI in some way. This would probably only make sense if your application needs to perform aggreagation and time-consuming calculations before updating the GUI. In the same way that you don't want to block your IO threads, you don't want to block your GUI thread.
Use shared buffer and TTimer in main form
I mentioned earlier that the "intuitive idea" of a shared buffer, meaning: "different threads reading and writing at the same time"; exposes you to the risk of race conditions. If in the middle of a write operation you start reading data, then you risk reading data in an inconsistent state. These problems can be a nightmare to debug.
In order to avoid these race conditions you need to fall back on other synchronisation tools such as locks to protect the shared data. Locks of course bring us back to the blocking issues, albeit in a slightly better form. This is because you can control the granularity of the protection desired.
This does have some benefits over messaging:
If your data structures are large and complex, your messages might be inefficient.
You won't need to define a rigorous messaging protocol to cover all update scenarios.
The messaging approach can lead to a duplication of data within the system because the GUI keeps its own copy of the data to avoid race conditions.
There is a way to improve the idea of shared data, only if applicable: Some situations give you the option of using immutable data structures. That is: data structures that do not change after they've been created. (NOTE: The message objects mentioned earlier should be immutable.) The benefit of this is that you can safely read the data (from any number of threads) without any synchronisation primitives - provided you can guarantee the data doesn't change.
The best approach is to use a GDI custom message and just call PostMessage() to notify the GUI.
type
TMyForm = class(TForm)
.
.
.
private
procedure OnMyMessage(var Msg: TMessage); message WM_MY_MESSAGE;
procedure OnAnoMessage(var Msg: TMessage); message WM_ANO_MESSAGE;
.
.
PostMessage(self.Handle,WM_MY_MESSAGE,0,0);
See this great article for full explanation.
This is a lighter/faster approach to rely on the OS internal features.

Is it safe to set the boolean value in thread from another one?

I'm wondering if the following (pseudo) code is safe to use. I know about Terminated flag but I need to set some sort of cancel flag at recursive search operation from the main thread and keep the worker thread running. I will check there also the Terminated property, what is missing in this pseudo code.
type
TMyThread = class(TThread)
private
FCancel: Boolean;
procedure RecursiveSearch(const ItemID: Integer);
protected
procedure Execute; override;
public
procedure Cancel;
end;
procedure TMyThread.Cancel;
begin
FCancel := True;
end;
procedure TMyThread.Execute;
begin
RecursiveSearch(0);
end;
procedure TMyThread.RecursiveSearch(const ItemID: Integer);
begin
if not FCancel then
RecursiveSearch(ItemID);
end;
procedure TMainForm.ButtonCancelClick(Sender: TObject);
begin
MyThread.Cancel;
end;
Is it safe to set the boolean property FCancel inside of the thread this way ? Wouldn't this collide with reading of this flag in the RecursiveSearch procedure while the button in the main form (main thread) is pressed ? Or will I have to add e.g. critical section for reading and writing of this value ?
Thanks a lot
It's perfectly safe to do this. The reading thread will always read either true or false. There will be no tearing because a Boolean is just a single byte. In fact the same is true for an aligned 32 bit value in a 32 bit process, i.e. Integer.
This is what is known as a benign race. There is a race condition on the boolean variable since one thread reads whilst another thread writes, without synchronisation. But the logic of this program is not adversely affected by the race. In more complex scenarios, such a race could be harmful and then synchronisation would be needed.
Writing to a boolean field from different threads is thread safe - meaning, the write operation is atomic. No observer of the field will ever see a "partial value" as the value is being written to the field. With larger data types, partial writes are a real possibility because multiple CPU instructions are required to write the value to the field.
So, the actual write of the boolean is not a thread safety issue. However, how observers are using that boolean field may be a thread safety issue. In your example, the only visible observer is the RecursiveSearch function, and its use of the FCancel value is pretty simple and harmless. The observer of the FCancel state does not change the FCancel state, so this is a straight / acyclic producer-consumer type dependency.
If instead the code was using the boolean field to determine whether a one-time operation needed to be done, simple reads and writes to the boolean field will not be enough because the observer of the boolean field also needs to modify the field (to mark that the one-time operation has been done). That's a read-modify-write cycle, and that is not safe when two ore more threads perform the same steps at just the right time. In that situation, you can put a mutex lock around the one-time operation (and boolean field check and update), or you can use InterlockedExchange to update and test the boolean field without a mutex. You could also move the one-time operation into a static type constructor and not have to maintain any locks yourself (though .NET may use locks behind the scenes for this).
I agree that writing a boolean from one thread and reading from another is thread safe. However, be careful with incrementing - this is not atomic and may cause a decidedly non-benigh race condition in your code depending on the implementation. Increment/Decrement normally turns into three seperate machine instructions - load/inc/store.
This is what the InterlockedIncrement, InterlockedDecrement, and InterlockedExchange Win32 API calls are for - to enable 32-bit increment, decrement, and loads to occur atomically without a seperate synchronization object.
Yes it is safe, you need to use Critical Sections only when you are reading or writing from/to another thread, within same thread it is safe.
BTW. the way you have RecursiveSearch method defined, if (FCancel = False) then you'll get an Stack overflow (:

Delphi threading - which parts of code need to be protected/synchronized?

so far I thought that any operation done on "shared" object (common for multiple threads) must be protected with "synchronize", no matter what. Apparently, I was wrong - in the code I'm studying recently there are plenty of classes (thread-safe ones, as the Author claims) and only one of them uses Critical Section for almost every method.
How do I find what parts / methods of my code needs to be protected with CriticalSection (or any other method) and which not?
So far I haven't stumbled upon any interesting explanation / article / blog note, all google results are:
a) examples of synchronization between thread and the GUI. From simple progressbar to most complex, but still the lesson is obvious: each time you access / modify the property of GUI component, do that in "Synchronize". But nothing more.
b) articles explaining Critical Sections, Mutexes etc. Just a different approaches of protection/synchronization.
c) Examples of very very simple thread-safe classes (thread safe stack or list) - they all do the same - implement lock / unlock methods which do enter/leave critical section and return the actual stack/list pointer on locking.
Now I'm looking for explanation which parts of code should be protected.
could be in form of code ;) but please don't provide me with one more "using Synchronize to update progressbar" ... ;)
thank you!
You are asking for specific answers to a very general question.
Basically, apart of UI operations, you should protect every shared memory/resource access to avoid two potentially competing threads to:
read inconsistent memory
write memory at the same time
try to use the same resource at the same time from more than one thread... until the resource is thread-safe.
Generally, I consider any other operation thread safe, including operations that access not shared memory or not shared objects.
For example, consider this object:
type
TThrdExample = class
private
FValue: Integer;
public
procedure Inc;
procedure Dec;
function Value: Integer;
procedure ThreadInc;
procedure ThreadDec;
function ThreadValue: Integer;
end;
ThreadVar
ThreadValue: Integer;
Inc, Dec and Value are methods which operate over FValue field. The methods are not thread safe until you protect them with some synchronization mechanism. It can be a MultipleReaderExclusiveWriterSinchronizer for Value function and CriticalSection for Inc and Dec methods.
ThreadInc and ThreadDec methods operate over ThreadValue variable, which is defined as ThreadVar, so I consider it ThreadSafe because the memory they access is not shared between threads... each call from different thread will access different memory address.
If you know that, by design, a class should be used only in one thread or inside other synchronization mechanisms, you're free to consider that thread safe by design.
If you want more specific answers, I suggest you try with a more specific question.
Best regards.
EDIT: Maybe someone say the integer fields is a bad example because you can consider integer operations atomic on Intel/Windows thus is not needed to protect it... but I hope you get the idea.
You misunderstood TThread.Synchronize method.
TThread.Synchronize and TThread.Queue methods executes protected code in the context of main (GUI) thread. That is why you should use Syncronize or Queue to update GUI controls (like progressbar) - normally only main thread should access GUI controls.
Critical Sections are different - the protected code is executed in the context of the thread that acquired critical section, and no other thread is permitted to acquire the critical section until the former thread releases it.
You use critical section in case there's a need for a certain set of objects to be updated atomically. This means, they must at all times be either already updated completely or not yet updated at all. They must never be accessible in a transitional state.
For example, with a simple integer reading/writing this is not the case. The operation of reading integer as well as the operation of writing it are atomic already: you cannot read integer in the middle of processor writing it, half-updated. It's either old value or new value, always.
But if you want to increment the integer atomically, you have not one, but three operations you have to do at once: read the old value into processor's cache, increment it, and write it back to memory. Each operation is atomic, but the three of them together are not.
One thread might read the old value (say, 200), increment it by 5 in cache, and at the same time another thread might read the value too (still 200). Then the first thread writes back 205, while the second thread increments its cached value of 200 to 203 and writes back 203, overwriting 205. The result of two increments (+5 and +3) should be 208, but it's 203 due to non-atomicity of operations.
So, you use critical sections when:
A variable, set of variables, or any resource is used from several threads and needs to be updated atomically.
It's not atomic by itself (for example, calling a function which is guarded by critical section inside of the function body, is an atomic operation already)
Have a read of this documentation
http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/ToC.html
If you use messaging to communicate between threads then you can basically ignore synchronisation primitives completely because each thread only accesses its internal structures and the messages themselves. In essence this is far easier and more scalable architecture than using synchronisation primitives.

Resources