Locks - do they really serve any purpose?
g3cwi
Posts: 262
I am starting to explore the Propellor Locks. If I understand the manual correctly these are not really locks in that nothing is locked by them. If that is the case I wonder what additional benefits they offer over simply setting a flag at a particular memory location?
Regards
Richard
Regards
Richard
Comments
http://forums.parallax.com/showthread.php?109727-Does-anyone-use-LOCKs
Last post by Lonesock makes me wonder if the SD card reading code, FSRW, uses locks or not.
I'm also wondering if Locks are in Prop2 or if Chip decided to drop them...
If you think about this a bit you will see it cannot be done with simple flags that you read and write.
If the flag is clear when you read it, indicating you have access, how do you know someone else has not also read it as clear before you right back "not clear". If they have then then you will both be writing/reading the data structure at the same time and corrupting it.
Have a google for "mutual exclusion" or "atomic locks" I'm sure you will find something that explains it well.
However in many cases you can get by with no lock. A single reader process and a single writer process can cooperate with just simple flags or other means.
Have a look at how FullDuplexSerial works for the classic exa.ple.in the Propeller world.
With all that said, there still need to be rules about using locks in your code to protect memory (pins, code, etc.). If any code that changes a shared structure and wants to be be safe, it should lock the lock the lock associated with the structure (wait, if it can't be locked), manipulate the structure, then unlock the lock associated with the structure. If you want to break the rules, you can write code that ignores the lock and just manipulates the structure. The lock doesn't really protect anything, it just gives you a tool to create an agreement in your code that can be protected if everybody follows the rules.
Make sense?
I've noticed Kye's objects you locks.
I haven't had many cases when a flag wouldn't do but I was glad to have the locks in those few cases.
Unless some problem comes up, I'm pretty certain that the instruction set in v2.0 is golden, not subject to change.
My head has gone all funny!
Ok, thinking further, in the world of parallel processing, I wonder if there could be things one could learn from the most powerful parallel processor in the known universe? (ie that thing between your ears).
Rather than having locks which are an all or nothing affair, how about a numerical value associated with how much a process needs to access a shared resource. As the desire for access increases, so does its numerical value. For a biological example, think of your desire for food after a meal, 5 hours after a meal and 2 days after a meal. Actually, many biological desires work like that. Food. Sleep. Bladder. Bowel. Reproduction.
So thinking further, if the organism as a whole (ie the propeller chip) is not doing very much, it can afford to process the occasional serial byte that has come in, or the odd keypress.
But as the overall processing increases, this could be a way to prioritise things. The serial buffer that is almost full is like the kid at the back of the classroom with his hand up saying "please Miss, I *really* need to go to the bathroom".
I wonder if this might give smoother control overall. Or to use the analogy of all-or-nothing locks, you don't want that kid to get all the way to the bathroom to then find the door is locked!
Locks are software only locks. That is, it is up to the software to acknowledge the use of the locks. There is no hardware protection provided by these locks, so its up to the programmer.
Locks provide a simple mechanism to the programmer. We could implement locks in hub using a number of instructions to achieve the same thing. The lock instructions are easier.
However, locks are hardly required because we tend to only require co-operation between cogs. An example is in Kye's SD driver. The upper cog ensures the command flag is clear (the slave cog driving the SD card) is no longer doing anything (it shouldn't because the upper cog is now going to set something) which indicates the upper cog can give the driver/slave a command. If ok, he sets up some parameters for the driver, and lastly sets the command flag that tells the driver that all parameters are set and to go do something. The driver should be waiting for the command flag to be set to something. When set, the driver determines using the flag and parameters, what it is to do, and when done, returns any parameters or buffers, and lastly clears the command flag to indicate it has completed its job.
Kye also uses locks in his SD code. IIRC that is for when the driver may be used by multiple threads to access the driver. I say threads meaning that it could be multiple cogs, or it could be one cog that accesses more than one file on the sd card. This ensures that the common parameters required for the driver are not inadvertantly changed - i.e. it is a protection mechanism for poorly written user code above Kyes upper and driver/slave code. (it is quite hard to explain)
It would have been nice to have more locks in P2, but as long as there is at least one hardware lock we can implement as many lock as we need in software.
- GCC needs locks as pthreads uses locks
- Morpheus needs locks
I am sure other applications use them too.
In general, designing concurrent access to resources with significant state
like secure digital cards can be challenging. (What if one thread changes
the "current directory"; how does it "inform" the other thread? Or is there
some per-thread structure that is allocated to maintain this information?
A lock itself is not sufficient; nor is "separate file" support.)
Then you could have any many locks as you need.
Mike: Locks can be achieved using the existing instruction set. But using the instructions is far easier and less prone to errors. Of course the priority has been reversed because the last to claim it in a loop will get it.
Here is an example...
rockiki: Kye can have multiple files open at a time. Locks are his protection from higher level coding errors when multiple versions of his code are running. BTW did you do the later mb-rawb-spi26 code that lonesock released?
Locks are often resolved by read-modify-write. This could be achieved in a different way on any hub location by having an instruction that writes to hub memory and returns a condition code if that hub memory was zero before the write. But of course, this would mean complicating hub memory and I would think this would most likely require the hub access to become 2 cycle.
IMHO we need the locks, and that is what appears to be in P2 anyway.
And this is exactly why it is the easiest way to have locks. What you try to accomplish with lockptr is a real atomic operation for the lock instruction.
This is not true. In the general case of multiple readers and writers it is not possible to guarantee data integrity without some kind of atomic read/write operation. It is impossible to do it on the Prop without using the locks.
Drat, I said "impossible", now someone will show how to do it:)
But besides wasting codespace you also waste time, thus a lock is much better!
That means:
1. A chain can be formed of processes linked by fifos. For each fifo there is only one writer and one reader so all is safe.
2. We can now loop the end of the chain back to the first process, via another fifo, and circulate data safely around the loop.
3. The processes now pass a "token" from node to node around the loop. That is to say that if a node has just received some special message it is said to hold the token. If it has just sent that message on down the line it then it no linger holds the token.
4. Whichever process holds the token is allowed to access a resource that they all share. When done with the resource the token is passed on.
Ergo, we don't need locks to achieve mutual exclusion between multiple readers and writers.
Cluso, my apologies, I think I have proved myself wrong.
If it woks for sharing time on a network cable, the token ring LANs, it should be sound.
Is it so that I have missed a point here and Cluso's lock loop is actually is safe?
Looking at it I was forgetting where I am and that on the Propeller:
1) There are no interrupts to introduce arbitrary delays between wrbyte and rdbyte.
2) Access to HUB is forced to follow the round robin cycle.
Is it so that given those conditions the lock loop is safe? Thinking it through some more....
Now what about doing it from Spin? At first sight it looks like all bets are off.
I am not sure spin could achieve the same, and certainly not a mix of spin and pasm. But, we could "nobble" spin to implement the pasm code
1st read has to take place when each COG can be sure that no other COG will update it in the next few instructions
write for all COGs has to take place in the exactly same HUB-cycle
2nd read for checking has to take place after that write cycle
Tokens of course solve the problem, but would you really prefere a token implementation over the locks? Where do you find token ring hardware these days? ;o)
Anyway my token ring need no hardware but the Prop.