That can cause a race condition because if 'f1' makes it to "left = false" and pauses execution for 'f2' to make it to "right = false", then both function will be blocking each other on the second "while" loop.
The shared resource in your example is obviously a problem in concurrent programming only. Game Maker never preempts function calls, so yes, this kind of behaviour is avoided. This does not mean all timing issues when writing game maker code are avoided. Notably the ones I listed above, whereby the result of a shared variable depends entirely on the timing of the game, which is controlled by instance IDs, not explicitly by the programmer. (Unless of course they perhaps delete all objects in a room and re-adding them in the begin step, but I've not known any game maker program/programmer to do this, it's just a waste of resources).
GM would run 1 function first, then run the second function next...there is no race condition, the functions complete before execution is returned for the next task. Like I said, YOU are ignoring this in order to cause an infinite loop somehow, this doesn't mean it's a race condition.
Function preempting is not the only thing that can cause race conditions. Anything where a shared resource is controlled by timing of events can be a race condition. I'm not saying game maker preempts code, I'm
not saying game maker has deadlocks. All I'm saying is that the outcome of the step event over multiple instances is controlled by the timing of the step event, which is usually not defined by the programmer.
You read that wrong....after GM runs all events of all objects that are activated for that step, it puts itself to sleep based on how much time has passed versus the room_speed. This does not affect the code itself at all...when the OS has decided the sleep is finished, it returns back to GM to run the next step in all code in the same order it did last cycle.
I'm sorry, but you read that wrong. I wasn't talking about game maker's sleeping and it's process allocation in regards to the OS. I was talking about how game maker schedules it's instances inside the step event is akin to how an OS schedules processes to avoid starvation.
No you can't, the entries in the table have nothing to do with the task given to each process...nor whether they have put themselves to sleep, or waiting for a specific Semaphore event to occur. You can _guess_ what will be run next on the processor, but not only would you be wrong 99% of the time, but you wouldn't know how long the processor will give that operation (whether it be 1 opcode, or 100).
Yes, I was wrong, the process table is not the appropriate thing to look at, what I mean was the queue. Most operating systems manage a queue of processes (usually a priority queue, but that's semantics). The next entry in the queue will be the next entry run. Usually it's a very straightforward algorithm. Once the process on the top of the queue is run, then it is put on the end and the next process is run.
A process waiting on I/O will not be on this queue until an interrupt happens. When an interrupt occurs, the waiting process is simply moved from the waiting heap and put onto the end of the queue. (if there happens to be nothing in the queue it will run straight away)
This is no different to game maker having a "queue" of instance ids, and running their step events in turn.
As for how long the process is run on the processor, it doesn't matter. The OS will schedule a certain number of interrupts based on priority, if the processes ends before it uses up their time, the next process in the queue will be run. If the processes doesn't finish in time, then it will be preempted, and the next one will be run anyway. You still know the exact order in which the processes will be run, as in game maker.
The way the operating system schedules processes in this fashion is analogous to how game maker schedules instances in the step event.
There is no analogy because GM is 1 thread, not multi-threaded. Each object is run fully and sequentially each step regardless whether it has CPU time or is stalled. GM doesn't just go to ObjectA and put it's code on the processor and say "oh noes, windows forced it off the processor, let me put ObjectB there instead and come back to ObjectA later"....GM doesn't do that.
An instance is either not in the list to be run, or in the list to be run....and if it's in the list, when GM comes to it, it will run it. It will continue to run it until the code is finished, then it will go to the next one in the list
This logic is very wrong. According your your train of thought, user level concurrency (of which there are hundreds of different ways to implement, many of which are nearly the same as Game Maker's, including things like coroutines) would be race condition free, simply because they aren't multi-threaded. Multi-threading has nothing to do with race conditions. Race conditions are
important in multi-threaded environments, mostly because of deadlock, but this does
not mean that programs run along a single thread of execution are free of all race conditions.
The OS doesn't ensure anything...at all. GM may ensure an instance will get it's time to run the code each game step....an OS could block a program from running altogether because it's busy doing something else entirely. The time it gives each thread is not the same, so some code may run more than others...while GM may take different times processing each instance, it still processes each instance _fully_ before moving to the next, so the code it runs is the same each time.
Your very wrong on this point, to quote wikipedia (it's wikipedia, I know, not the best source, but w/e):
... Modern scheduling algorithms normally contain code to guarantee that all processes will receive a minimum amount of each important resource (most often CPU time) in order to prevent any process from being subjected to starvation.
Edited by sylvan, 22 November 2010 - 03:21 AM.