Accidents will happen without a traffic light…Now this problem can come in various forms in data, like:Multiple writes at the same time.
Reads and writes at the same time.
Multiple reads at the same time.
Trying to read before something is written.
So we need to control and prevent these cases if we dont want to have a corrupted memory.
One solution is to program explicitly by using locks and semaphores.
But this can take time to implement and can complicate the development quite a bit.
And the other solution is to use data structures which already have these implementations in place, and by using their dedicated methods we can have the same result without much of the difficulty.
And these collections are Thread-Safe Collections.
What? — So Thread-Safe Collections are collections which can be accessed by multiple threads simultaneously while being free of race conditions.
By the name, we can directly understand that it’s a collection which is safe to be accessed by a thread at any point in time.
More concretely it could be a dictionary, a FIFO queue, a LIFO stack which enables adding/removing items without needing to explicitly program the synchronisation.
Basically it is a concurrent data structure that is more practical to program with.
How? — Well now that we see the problem and learned some vocabulary, we’ll illustrate how it works.
Well lets get back to the 4 problems mentioned earlier.
There are many solutions, but here we will just illustrate some basic ones using the state machine below:State machine of a basic Thread-Safe CollectionSo first thing first, if the mutex is locked, we wait until it is unlocked for any function.
When we lock the mutex, only the thread that locked it will have access to the data, and every other thread will have to wait until it is unlocked.
The first 2 problems can be solved simply.
If we need to write, we lock the mutex, we write, and then we unlock.
When we have multiple readers, it’s not a big problem as long as the data is not modified during reading.
So we lock the data for writers using RLock and all the readers can read the data, and the last reader thread unlocks the mutex when it is done.
And for the 4th problem.
We need to be able to check if there is an available value, if yes, we read the value.
But if it isn’t available we wait until there is an available one!How to use? — So now that you know what they are, and need to use them, lets see how to use them.
Every standard programming language has an implementation of at least one concurrent data structure.
The most simple one is a FIFO queue.
To illustrate a solution in multiple languages, we will use a Producer/Consumer problem in which the Producer outputs much slower that the Consumer can consume.
Which relates to the “Trying to read before something is written” problem mentioned above.
The program will be fairly simple.
We will have a thread that produces a value every 1 second.
And a consumer thread in parallel which consumes a value as soon as it can.
The problem with non thread-safe data would be that the consumer would create an error trying to consume a value it cannot have.
Meanwhile here, it would just wait until the value would be ready.
So let’s see this code in 3 different programming languages, in Java, Python and Golang.
JavaSo in java you can use the “java.
Which includes:BlockingQueue which is a blocking FIFO queue.
ConcurrentHashMap which is a concurrent analog of HashMapConcurrentSkipListMap which is a concurrent analog of TreeMap.
Here you can see an example with BlockingQueue:BlockingQueueExample in Java using an ArrayBlockingQueueNow if you run the code above you get this:It can be seen that we cant consume without producing an item beforehand.
PythonIn Python we have some as well like:Queue which implements a FIFO, LIFO and PriorityQueueDeques support thread-safe, memory efficient appends and pops from either side.
So lets see the same program as in Java but implemented in Python:BlockingQueueExample implemented in PythonAnd by running the code above, we naturally get the same result:The result from executing the exampleGOBut in Golang, we have a different approach to Thread-Safe Collections.
We don’t have a basic queue implementation in go.
In Go we use channels which make the code much easier to read:ChannelExample in GolangAnd of course, we get the same result:The result from executing the exampleIn a nutshell!.Thread-Safe Collections are very practical in multi-thread programming, by facilitating much of the development.
The most basic example of one of these collections is a Queue, which classical programming languages already have implemented.
And we can modify these data structures, to read and write values, comfortably using the methods already put into place without any concurrency problems.
concurrent (Java Platform SE 8 )A stage of a possibly asynchronous computation, that performs an action or computes a value when another…docs.
Queue – A synchronized queue class – Python 2.
15 documentationNote The module has been renamed to in Python 3.
The tool will automatically adapt imports when converting your sources…docs.
orgGo by Example: ChannelsChannels are the pipes that connect concurrent goroutines.
You can send values into channels from one goroutine and…gobyexample.
comThread-Safe CollectionsThe .
NET Framework 4 introduces the System.
Concurrent namespace, which includes several collection classes…docs.
comOracle Solaris 11.
4 Information LibraryDocumentation Home " Oracle Solaris 11.
4 Information Librarydocs.