- 8,947
- 687
As mentioned before, those "bullets" or "connectors" are the equivalent of branch target labels in pseudocode.sandy.bridge said:Alright, let's see if I was able to capture that idea with the attached flow chart.
As mentioned before, those "bullets" or "connectors" are the equivalent of branch target labels in pseudocode.sandy.bridge said:Alright, let's see if I was able to capture that idea with the attached flow chart.
That's the "race condition"; No telling which path will be the last one to set the variable's value.sandy.bridge said:Okay, and what happens when the conditional gets X=0 and X=1 at the same time?
Ha!And in the last atomic action where you wrote "Do something clever", are you referring to me? Is this my time to shine?
sandy.bridge said:Interesting. So not only is there a race condition, both 1=1? conditions cannot really be converted to pseudo-code because there is no path from the start box to those conditions, correct? From what I know, you start at "START", and end and "STOP", and therefore those conditions would not be able to be represented between START and STOP.
One method for multi-threading psuedocode is to use sequences. All sequences in this example would start and run at the same time in parallel. To duplicate the race condition in your flowchart with pseudocode, but without the uneeded conditionals:sandy.bridge said:both 1=1? conditions cannot really be converted to pseudo-code because there is no path from the start box to those conditions, correct?
sequence
x = 1
endsequence
sequence
x = 0
endsequence
sequence
if(x == 1)
then docleverthing
endsequence
rcgldr said:The structure of the race condition flow chart is faulty. You can't have 3 parallel threads of code merge into a single thread.
You're running three threads at the same time, at least initially. The flow chart implies that the three threads become one thread where the arrows connect in at the middle.sandy.bridge said:So are the threads going to come together at any joints at all? Or are we merely running the three threads at the same time?
The threads weren't "merged", instead threads were terminated and the results pass on to other threads pending on the termination and output from those spawned threads. On the CDC and Cray machines (and I assume many current processors), some out of order and parallel operations on registers were handled via register "scoreboarding", a hardware scheme which was used to indicate that a register was "waiting" for the output from some operation, suspending any operations wanting to use that register as input. I don't think there was any form of hardware "scoreboarding" for memory, so that required a software handshake (mutex, semaphore, ...).gneill said:Cray had a form of parallelism called autotasking, implemented at the compiler/library level. With it logical threads could be spawned, merged, and dismissed automagically.
It can be converted into psuedo code, but you need a convention on how to describe parallel threads with pseudo code, and operators that can pend on actions (including spawning and termination) between threads.sandy.bridge said:Why exactly can't it be converted into pseudo-code then?
In this case we can only assume the rules are as given, no more, no less. Whether they are complete, correct, sufficient, or permit the construction of illogical or flawed structures is not at issue. In fact, here we are trying to find just such a situation for the given rules. Also the underlying implementation of what the flowchart describes is not particularly relevant, even if we know how it's "really done" in real world implementations. By assuming the worst we can might be able to answer the questionrcgldr said:You're running three threads at the same time.
Depends on how "flowchart" was defined. Normally you can't have multiple states at the same instance in a flowchart, so the control flow can only be at one point in the flow chart at any time. In this case the flow chart starts with 3 control flows, then ends up with one.
The flowchart would be valid if those arrows from the outer threads connecting to the inner thread represented termination of those outer threads, and that the inner thread was pending on completion of both outer threads (order not important, so you still have the race condition) before continuing.
The threads weren't "merged", instead threads were terminated and the results pass on to other threads pending on the termination and output from those spawned threads.
Yes, the results were merged, and to the user it appeared that nothing had happened except that the code ran faster. In actuality the threads ("microtasks") had come into existence previously and hung around in a sleep state waiting to be called into a fray. At the end of a given fray the results were merged via semaphore mechanisms and the tasks would depart, returning to a wait state ("spinwait"), and eventually to sleep if not promptly summoned for more work (yielding up the physical CPU for rescheduling by the OS), and await another summons to a fray. For microtasking and autotasking the underlying tasks weren't continually destroyed and recreated because the instantiation cost was too high (OS call, resource allocation, rescheduling). Much more efficient to do it once at the beginning of a program, or for a chunk where parallelism is going to be used, and have them ready to go either spin-waiting or at worst, waiting for the attaching of an available CPU.
But the implementation details are not what the user saw (or rather, what they weren't supposed to have to see...).
No, no scoreboarding for memory, but there were shared registers and semaphore registers that could be used for managing memory based structures.In the case of register access, register "scoreboarding" was used to indicate that a register was "waiting" for the output from some operation, suspending any operations wanting to use that register as input. I don't think there was any form of hardware "scoreboarding" for memory, so that required a software handshake (mutex, semaphore, ...).
In that case, you could simply allow multiple threads to be running the same code with the same variables but out of sync and running at different speeds to create all sorts of problems. For example, take the pseudocode casegneill said:In this case we can only assume the rules are as given, no more, no less. Whether they are complete, correct, sufficient, or permit the construction of illogical or flawed structures is not at issue. In fact, here we are trying to find just such a situation for the given rules.
rcgldr said:Rcgldr: The threads weren't "merged", instead threads were terminated and the results pass on to other threads pending on the termination and output from those spawned threads.
I only meant logically. The unused tasks would be in an idle / pending state when there was nothing for them to do. Also some of this out of order processing uses the equivalent of hardware multi-tasking that doesn't involve the OS, such as multiple arithemetic units on a single processor running at the same time, which the OS would be unaware of (the hardware would usually handle this with some form of scoreboarding).gneill said:For microtasking and autotasking the underlying tasks weren't continually destroyed and recreated because the instantiation cost was too high (OS call, resource allocation, rescheduling).
You start with three threads running unsynchronized. The merging arrows would (or at least should) imply synchonization, with the middle thread waiting for both outer threads to terminate (or go idle as gneill pointed out), but in no specifc order (wouldn't matter which one terminated first). You could also invent other conventions for syncrhonization between threads.sandy.bridge said:So essentially you have two threads running in synchronization, and then the third thread is evaluated after the first two are declared? Or are all three threads to be running in parallel and synchronized?
You could assume that it's implied by the merging arrows, but that would require a brief explanation. Otherwise, you need to create some convention for threads to signal or pend on events, in either your flowcharts or your pseudocode.sandy.bridge said:Is there a way to represent the "pending" of the middle thread to show that it is waiting for the side threads via flow chart? Or would I just have to have a brief explanation?
How would you distinguish between iteration and recursion with a flow chart? In the case of flowcharts or pseudocode, there would need to be some convention to describe a recursive call (as opposed to creating what would appear to be a loop back to the start of the code).jedishrfu said:I think the point may be that recursion can be represented on a flowchart (tieing an if back to itself) whereas it can't be represented by psuedocode unless there's a provision for defining a method/function/subroutine in the pseudocode.
I would assume that the actions of a block are described as text within the block, and in that case why couldn't similar text be used in pseudocode?sandy.bridge said:Well, I emailed my professor and he essentially shot down all this work regarding this question. I do, however, have a hint: what implicit rules are there regarding performing the actions of a block, and is there a way to create a flow chart that violates one or more of these said rules.
I'd wait until the professor actually gives an example of a flowchart that can't be duplicated with pseudocode, assuming you're allowed to bend the rules in the same manner for both methods.sandy.bridge said:I'm starting to think that I am spending far too much time on this question.