So the one thing that we haven't really thought about in the implementation of the observable.
Let me actually bring this up is Thread safety because remember what's happening here is behind the
scenes we have a vector and we have different calls like notify subscribe and indeed unsubscribe which
are being used and we've assumed they've been using them from a single thread.
But what if you have them on different threads.
Well then it's going to be a real problem like for example here we are modifying the collection.
And here we are integrating the collection so vector is not a thread safe class and doing this kind
of thing is quite simply dangerous.
Now you could be using something other than vector here like an as to said for example but that doesn't
change the problem.
We still need to provide some sort of thread safety mechanism.
Now luckily for us we can actually do that relatively easy.
So let's make a new class I'm going to call it a safer observable so a safer observable just as the
name suggests is going to be slightly slightly safer than an ordinary observable we're going to add
additional safety mechanism.
So let me actually copy all of this stuff from observable I'll put it into a safer observable and then
we can just modify a few things here.
So call this safer observable and we can we can add additional safety checks here.
So the most obvious thing that you can do is just stick a lock into every single one of these functions
so that only one of them can be executing at any given moment in time.
This protects the observer's vector from being modified while it's iterated for example.
So the way I would do this is as follows.
Let me actually I'm going to typedef the kind of mutex that I would be using to actually set up the
scoped lock in each of these methods.
So I'll typedef.
Well let's typedef an orderly STV mutex to begin with to be our mutex on this Corti.
So here let me say I need the that includes which the line has hidden here so we need that mutex.
And then what we can do is we can actually make a scoped lock in every single one of these methods.
So as the scoped block and it is typed on the mutex on this Corti and I'll call it lock.
And here we need to provide a mutex so we need to actually make an instance of it mutex on this Corti
empty X and then stick empty X in here so we can replicate this in all of these three locations and
it would appear that the class is now thread safe.
We can go back to Maino CBP.
I can make this a safer observable and then we can sort of continue using this as before.
JR Of course.
Now we also need the safer observable detail before the whole thing to actually work.
So this approach is fine and I'm not even going to run that because essentially well you can assume
that it's more or less OK but there is a problem which is going to hurt us in certain situations.
And then there's the problem of a reentrancy.
So if we look at how safe are observable you can see that we have a lock here a lock here and the lock
here using the same mutex.
So what is the problem with this.
Well what if you for example call on Subscribe inside notify.
Now you're probably wondering.
Well hold on.
How is that going to happen.
So let me show you a setup where this is quite a realistic set up where this can happen.
Let's suppose that you have a component in your system called Traffic Administration.
Let's suppose that there is traffic administration now Traffic Administration is an observer off person.
Now let's suppose this Traffic Administration is only interested that you're not driving if you're too
young and when you get older it just stops monitoring you altogether.
So what we do is we implemented a field changed obviously And here we say well if the field name is
equal to age then we're going to do different things depending on how old you are.
So if you are too young if you if you are under 17 for example then we're going to print some warning.
So Whoa there you you're not old enough to drive.
So it's going to basically complain that you're too young.
However if you're old enough if your age is 17 or greater Let's suppose the traffic administration decides
to unsubscribe to this particular event.
It's no longer interested in actually monitoring the field changes.
So here what would happen is we would say something like OK we no longer care.
And then what they would do is say Source doth unsubscribe providing ourselves as the argument.
Now what would happen here let's just try to think about the sequence of invocations as this is all
happening.
So essentially we're calling unsubscribe in safer observable and we're calling it from within notify
because the reason why we got the notification is to notify.
So we took this law back here with a mutex and then we are trying to get to another scoped lock with
the same mutex.
So do you want to know what happens when you do that.
Well we can actually go ahead and write write a program which does exactly that.
Because here we have we have the consul person of Zobel we're going to have traffic administration Teej
and we're going to say P-Dog subscribe teej.
And then as you get older sort of 15 16 17 and so on.
And the point to when you turn 17 that's when traffic administration is going to try and unsubscribe
from those field changes.
And I suppose given that I already know what the outcome is going to be less actually wrap it into a
try catch so that we get to see what's going on here.
So I'm going to put a try around this.
Catch
exception of some kind and we can just print out what the exception says and I don't think it's going
to be particularly useful for us what we get the exception.
But we'll take a look at it anyway.
OK so let's run though.
All right.
So as you can see are we getting the message we're not old enough to drive twice which is OK.
And then we no longer care.
So that's the message we're expecting by then.
Oh we get an exception handler so oops device or resource busy device or resource busy so that's basically
talking about the mutex so the mutex is busy and we cannot take the mutex twice essentially.
So what can we do about this.
Well depending on how you want to go about it there is the kind of easy fix and there is the more complicated
kind of fixes so the easy fix is that you simply avoid this particular situation so you don't you don't
consider like calling us subscribe insight on subscribe or something which also can happen but we just
fix this particular problem.
So not a very durable approach but we're going to take a look at how that works.
So essentially if we go back and just say for observable let's suppose we decide we don't want to take
the law here we're going to avoid taking the lock here actively.
And the way to do this is to avoid changing the collection obviously because once you do the rim the
erase remove Adium Well you're in trouble.
So what you would do here instead is you would set the observer to no PCR which is only possible if
you have a vector.
I mean we have a vector here so we can set something to know PCR if you had a set for example you'd
be in trouble here as well.
So let's suppose that we find we get the iterator to just call as to the find we find the appropriate
observer.
So we say beginner observers and observers and we're looking for this particular observer.
And what we do then instead of instead of just removing it using the erase remove idiom is we said it's
a null so if it is not equal to observers then we start it equals here and then what we do when we have
notify is when we check for no.
So we say if observer and then and only then do we generate the fuel change notification.
Now what you could also do is you can take this erase remove idiom and actually stick it after you've
performed the notification so you could stick it here optionally.
But we can leave them as just a bunch of NOS anyway.
So this actually fixes this particular problem.
So if I execute this we're not going to see the oops anymore let me just show you this all right so
as you can see we're getting exactly the output that we expected.
So we no longer generate the exception quite simply because we're handling this particular situation.
So the other alternative and this should hopefully explain why I did a time def here is to go from an
ordinary mutex to a recursive mutex.
Now a recursive mutex is quite possibly the most hated structure if you go to sites like Stack Overflow
for example.
So this is an alternative that would actually fix this problem for all of the functions here in terms
of their re-entrance.
So this is something that you can consider using It's not a popular choice because there are certain
implications but using a recursive mutex actually fixes this problem outright.