I did not understand the paradigm run-to-completion about state machine (14.2.3.9.1 UML 2.5 spec). At one point he says:
"Run-to-completion means that, in the absence of exceptions or asynchronous destruction of the context Classifier object or the StateMachine execution, a pending Event occurrence is dispatched only after the processing of the previous occurrence is completed and a stable state configuration has been reached. That is, an Event occurrence will never be dispatched while the StateMachine execution is busy processing the previous one"
and in another:
"IMPLEMENTATION NOTE. Run-to-completion is often mistakenly interpreted as implying that an executing StateMachine cannot be interrupted, which, of course [of course?? NDR] would lead to priority inversion issues in some time-sensitive systems. However, this is not the case; in a given implementation a thread executing a StateMachine step can be suspended, allowing higher-priority threads to run, and, once it is allocated processor time again by the underlying thread scheduler, it can safely resume its execution and complete its event processing"
So, is possible or not interrupt the state machine?? A new high priority event can interrupt the current event dispatch?
Thanks
Mauro
The implementation note refers to hard- or software implementation on a higher level. The completion is only valid for the context of the state machine. This machine may run in a global context which can allow to interrupt the processing of the state machine. But the state machine will not notice this interruption and from its own view it still continues processing. So, as mentioned, the only issue is that the state machines personal watch will not run continuously but with irregular jumps. In normal business processes this can be neglected, but when dealing with real-time-processing, you might get into trouble.
"an Event occurrence will never be dispatched while the StateMachine execution is busy processing the previous one" means that a StateMachine will not select the next Event from its queue until its run-to-completion step is completed. This does not prevent the state machine itself or other state machines from sending further events into its queue, while the run-to-completion step is running.
Moreover, a run-to-completion step might become suspended in the case of a synchronous Operation Call; the run-to-completion step will later be resumed when the operation call is completed (possibly returning a value).
Related
Since Smalltalk scheduling is non-preemptive, processes must explicitly yield or wait on a semaphore
Does this mean that one object entering an infinite loop could stall the entire system?
the loop can be interrupted at any time. Even an atomic loop like [true] whileTrue can be interrupted before "executing" the true object
By what can it be interrupted?
It is the Virtual Machine who may interrupt the image. Under a normal execution flow, the VM is basically sending messages, one after the other. However, certain events may impact the natural flow of execution by interrupting it, if needed. While concrete examples may change from one dialect to the other, these usually correspond to OS events that need to be communicated to the image for their consideration.
An interruption may also be caused if the VM is running out of memory. In this case it will interrupt the image requesting it to do garbage collection.
Loops are interesting because they have the semantics of regular messages, so what happens is that the block of code inside the loop is evaluated (#value & friends) every time the loop repeats. So, you should think of loops as regular messages. However, this semantics is usually optimized so the re-evaluation is not explicitly requested by a Smalltalk message. In that case the VM will check for interruptions before executing the block. Thus, if you run
[true] whileTrue
before designating the object true as the current receiver (in this case, of no message) the VM will check whether there is any interrupt to pay attention to (in the same way it checks for interruptions before starting to execute any given method).
Most dialects implement some "break" keystroke that would produce a "halt" and open a debugger for the programmer to recover manual control.
Note that, depending on the dialect, an interruption may only consist of the signaling of a semaphore. This will have the effect of moving the waiting process (if any) to the ready queue of the ProcessScheduler. So, the intended "routine" may not run immediately but change to the ready state for the next time there is a process switch (at that level of priority).
The last example that comes to mind is the StackOverflow exception (no pun intended), where the VM realizes that it is running out of stack space and interrupts the image by signaling an exception.
You may also think of the #messageNotUnderstood: as an interruption generated by the VM when it realizes that an object has received a message for which is has no implementation. In this case, the natural flow will change so that the object will receive the message #messageNotUnderstood: with the actual message as the argument.
One more thing. Whether a loop may or may not stall the system depends on the priority of the process it is running. If the loop is running with low priority an interruption that awakes a process of higher priority will take precedence and be run while the loop is sent to sleep. By the same logic, if your endless loop runs in a process at a higher priority no interruption will stop it.
Yes, it is super simple to just run
[ true ] whileTrue: [ ]
and you won't be able to do anything else.
Pharo has a "ripcord" when you press comand + . on Mac. For Windows or Linux it's either alt or control. This action should halt the thing that you are running and allow you to intervene.
I understand a Clojure "agent" is a ref with an added work queue of "actions". Actions are functions that are called with the ref's value at first position and can be passed additional parameters. Actions return a new value for the ref. Thus an "agent" is a device which computes ref := (action_[n] ° action_[n-1] ° action_[n-2] ° ... ° action_[1] ° action_[0]) (ref), likely with action-induced side-effects.
A call (send-off agent action & args) results in action being enqueued for asynchronous processing by a separate thread assigned by the system to the agent (from a growable thread pool, as I understand, and once the agent's queue is empty, the thread is either stopped or goes back into the pool).
A call (send agent action & args) results in action being enqueued for asynchronous processing by thread from a fixed system pool, where the thread is switched between actions belonging to multiple agents. In that case, the action should avoid blocking or hogging the thread for all too long.
So far so good, but what happens if some actions are enqueued with send and some with send-off to the same agent? Will the system switch between its two processing modes as it dequeues the action from the agent's queue?
The only difference between send and send-off is which thread group is used. The scheduling of the agent and a thread is (must be) done separately.
The only reason there are 2 thread groups in the first place is so that the send can be used for "fast running" tasks (eg in-memory/non-network operations). Tasks that are "slow" (e.g. network calls) are supposed to use send-off so they don't block the "fast" tasks.
The definition of "fast" and "slow" is vague and up to the user. Notice the difference in language here for send vs send-off (for "potentially blocking actions" like disk or network I/O):
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/send
More info here: https://clojure.org/reference/agents
The actions of all Agents get interleaved amongst threads in a thread
pool. At any point in time, at most one action for each Agent is being
executed. Actions dispatched to an agent from another single agent or
thread will occur in the order they were sent, potentially interleaved
with actions dispatched to the same agent from other sources. send
should be used for actions that are CPU limited, while send-off is
appropriate for actions that may block on IO.
I think you have send and send-off backwards: send uses a fixed-size threadpool, while send-off uses an unbounded threadpool.
But this makes no difference to the agent: actions are added to the agent's single queue, with a little note attached saying how they should be executed when the agent is ready to execute them. The agent always executes those actions sequentially, one at a time.
See for yourself: dispatch(IFn, ISeq, Executor) forwards to dispatch(Action), which forwards to enqueue(Action).
This is really a question confusing me for a long time. I tried googling a lot but still don't quite understand. My question is like this:
for system calls such as epoll(), mutex and semaphore, they have one thing in common: as soon as something happens(taking mutex for example, a thread release the lock), then a thread get woken up(the thread who are waiting for the lock can be woken up).
I'm wondering how is this mechanism(an event in one thread happens, then another thread is notified about this) implemented on earth behind the scene? I can only come up with 2 ways:
Hardware level interrupt: For example, as soon as another thread releases the lock, an edge trigger will happen.
Busy waiting: busy waiting in very low level. for example, as soon as another thread releases the lock, it will change a bit from 0 to 1 so that threads who are waiting for the lock can check this bit.
I'm not sure which of my guess, if any, is correct. I guess reading linux source code can help here. But it's sort of hard to a noob like me. It will be great to have a general idea here plus some pseudo code.
Linux kernel has a built-in object class called "wait queue" (other OSes have similar mechanisms). Wait queues are created for all types of "waitable" resources, so there are quite a few of them around the kernel. When thread detects that it must wait for a resource, it joins the relevant wait queue. The process goes roughly as following:
Thread adds its control structure to the linked list associated with the desired wait queue.
Thread calls scheduler, which marks the calling thread as sleeping, removes it from "ready to run" list and stashes its context away from the CPU. The scheduler is then free to select any other thread context to load onto the CPU instead.
When the resource becomes available, another thread (be it a user/kernel thread or a task scheduled by an interrupt handler - those usually piggy back on special "work queue" threads) invokes a "wake up" call on the relevant wait queue. "Wake up" means, that scheduler shall remove one or more thread control structures from the wait queue linked list and add all those threads to the "ready to run" list, which will enable them to be scheduled in due course.
A bit more technical overview is here:
http://www.makelinux.net/ldd3/chp-6-sect-2
I was reading about non preemptive threads and I found a slide from Princeton University and it shows the following diagram: (Source Link: http://www.cs.princeton.edu/courses/archive/fall11/cos318/lectures/L5_ThreadsImplementation.pdf)
From what I understood is that a thread to be executed is first put into a ready queue. When it pop's out of the queue it is in running state. If it wants to invoke another thread, it calls the yield function, which will store the current state of the thread and insert it in the tail of the queue. And the thread which is in the front of the queue will be executed.
What happens if The thread is blocked (i.e. it is waiting for some resource) ? I thought in non-preemptive thread it will wait for the resource and then carry on execution.
But from the below diagram it looks as though it goes into blocked state and then is put into the ready queue ? Why is that?
As said in the comments, non-preemptive means that another thread cannot interrupt (preempt) a running thread, not that the running thread won't yield when it has to wait for something.
When a thread is waiting for data from memory (for example), it's said to be in blocked state: its context is saved and another thread takes place in the computing resource (CPU core). When data is available in CPU's cache memory, then the first thread is said ready to resume its execution (and it will, as soon as it is the next to be executed and that the currently executed thread yields the computing resource).
This enables overlapping both data movements and threads execution, thus saving time by optimizing resource usage.
Suppose there is a process that is trying to enter the critical region but since it is occupied by some other process, the current process has to wait for it. So, at the time when the process is getting added to the waiting queue of the semaphore, suppose an interrupt comes (ex- battery finished), then what will happen to that process and the waiting queue?
I think that since the battery has finished so this interrupt will have the highest priority and so the context of the process which was placing the process on the waiting queue would be saved and interrupt service routine for this routing will be executed.
And then it will return to the process that was placing the process on the queue.
Please give some hints/suggestions for this question.
This is very hardware / OS dependant, however a few thoughts:
As has been mentioned in the comments, a ‘battery finished’ interrupt may be considered as a special case, simply because the machine may turn off without taking any action, in which case the processes + queue will disappear. In general however, assuming a non-fatal interrupt and an OS that suspends / resumes correctly, I think it’s unlikely there will be any noticeable impact to the execution of either process.
In a multi-core setup, the process may not be immediately suspended. The interrupt could be handled by a different core and neither of the processes you’ve mentioned would be any the wiser.
In a pre-emptive multitasking OS there's also no guarantee that the process adding to the queue would be resumed immediately after the interrupt, the scheduler could decide to activate the process currently in the critical section or another process entirely. What would happen when the process adding itself to the semaphore wait queue resumed would depend on how far through adding it was, how the queue has been implemented and what state the semaphore was in. It may be that it never gets on to the wait queue because it detects that the other process has already woken up and left the critical section, or it may be that it completes adding itself to the queue and suspends as if nothing had happened…
In a single core/processor machine with a cooperative multitasking OS, I think the scenario you’ve described in your question is quite likely, with the executing process being suspended to handle the interrupt and then resumed afterwards until it finished adding itself to the queue and yielded.
It depends on the implementation, but conceptually the same operating process should be performing both the addition of the process to the wait queue and the management of the interrupts, so your process being moved to wait would instead be treated as interrupted from the wait queue.
For Java, see the API for Thread.interrupt()
Interrupts this thread.
Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.
If none of the previous conditions hold then this thread's interrupt status will be set.
Interrupting a thread that is not alive need not have any effect.