Date post: | 17-Jan-2016 |
Category: |
Documents |
Upload: | silvester-owen |
View: | 225 times |
Download: | 0 times |
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Active Message Queues
Dr. Van Belle Wernere-mail: [email protected]
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Concurrency & Distribution Borg: a mobile multi agent system supporting strong mobility
of processes, distribution Seescoa: component oriented design in embedded systems,
supporting message queues, distribution BpmDj: music analysis tool; multiple competing analysis tasks
Modern [embedded] systems deal with multiple tasks. Most widely used abstraction: threads
Multiple threads/concurrent access managed through locks (pmutex) Although widely used this is a bad abstraction
Termination of threads Activation of threads Concurrency problems & Deadlocks between multiple threads
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Active Message Queues
Abstraction Runtime Precompiler
Abstraction Runtime Precompiler
Task Proxy
Task Impl
analyze(“song1.mp3”)
analyze(“song2.mp3”)
analyze(“song3.mp3”)
analyze(“song1.mp3”)
analyze(“song2.mp3”)
analyze(“song3.mp3”)
A queue in which messages can be pushed that will eventually be handled by a specific task
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Declaration task RhythmAnalyzer{message analyze(string filename, vector<sample>* audio, int p);}
task TempoAnalyzer{message analyze(string song);RhythmAnalyzer *rhythm;message set_rhythmlistener(RhythmAnalyzer*);};
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Task Implementation elementResult TempoAnalyzerTask::set_rhythmlistener(RhythmAnalyzer* r) { rhythm=r; return Done; }
elementResult TempoAnalyzerTask::analyze(string fn){ vector<sample>*audio=read_audio(fn); int period=… calculate tempo... rhythm→analyze(fn,audio,period); return Done;}
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Task Implementation (Cntd) elementResult RhythmAnalyzerTask::analyze(string fn, vector<sample>* a, int p) { vector<sample>* projection=...calculate... return Done; }
TempoAnalyzer tempotask;RhythmAnalyzer rhythmtask;
int main(int, char* []){ tempotask.set_rhythmlistener(&rhythmtask); tempotask.analyze(“song1.mp3”); tempotask.analyze(“song2.mp3”); tempotask.analyze(“song3.mp3”); ...
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Space Separation Each task is completely encapsulated in its own
object Each task is accessed through a proxy object All function calls to the proxy are pushed as
messaged into the Task Implementations' queue
The implementation object cannot be directly referenced
The messages should not be shared or be smartpointers to constants
Locks are unnecessaryLocks are unnecessary
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Time Separation When the proxy object is called it will queue the
message into the active object's implementation One does not wait for message 'returns' Tasks do not actively wait for one another
Deadlocks are impossibleDeadlocks are impossible
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Syntactical Separation Only messages can influence a task All messages that can influence a task are
declared at one place. provided through one proxy Implemented in one task implementation
1 task → 1 header & 1 implementation
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Threads vs Tasks Multiple tasks can be ran with 1 thread
TempoAnalyzerImpl::analyze(“song1.mp3”) TempoAnalyzerImpl::analyze(“song2.mp3”); RhythmAnalyzerImpl::analyze(“song1.mp3”,...,...); TempoAnalyzeImpl::analyze(“song3.mp3”); RhythmAnalyzerImpl::analyze(“song2.mp3”,...,...); RhythmAnalyzerImpl::analyze(“song3.mp3”,...,...);
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Threads vs Tasks Multiple tasks can be ran with multiple threads
TempoAnalyzerImpl::analyze(“song1.mp3”)
TempoAnalyzerImpl::analyze(“song2.mp3”)
TempoAnalyzerImpl::analyze(“song3.mp3”) RhythmAnalyzerImpl::analyze(“song1.mp3”,...
RhythmAnalyzerImpl::analyze(“song2.mp3”,...
RhythmAnalyzerImpl::analyze(“song3.mp3”,...
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Threads vs Tasks Multiple tasks can be ran with multiple threads
TempoAnalyzerImpl::analyze(“song1.mp3”)
TempoAnalyzerImpl::analyze(“song2.mp3”)
TempoAnalyzerImpl::analyze(“song3.mp3”)
RhythmAnalyzerImpl::analyze(“song1.mp3”,...
RhythmAnalyzerImpl::analyze(“song2.mp3”,...
RhythmAnalyzerImpl::analyze(“song3.mp3”,...
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Advantages Time/Space separation of tasks Tasks are independent from threads Syntactical encapsulation
Lockfree programming No deadlocks Efficient
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Problems Overview
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Double Activation (I) Assume we start a thread when the first
message is pushed from the proxy into the queue If we create the task thread directly we might have
multiple activations if two messages pushed at the same time.
Messages should only be handled when the queue actually changed. The message handler can leave certain messages in the queue
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Double Activation (I)
→ Lock the queue before pushing anything→ Lock the queue before pushing anything
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Double Activation (I) - solution
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Double Activation (II) The queue is locked to push the element
If it was the first element we start a thread This new thread directly pops the message and
starts dealing with it Another thread pushes again a new element and
starts a new thread since the queue is at this moment empty
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
→ Introduce a 'running' state in the task. If the task is already running, we don't start a new thread.
→ Introduce a 'running' state in the task. If the task is already running, we don't start a new thread.
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Missed Activation (I) Proxy checks running state and then locks the
queue. When the queue was empty, a thread is created only if the task was not yet running. Between the is_task_running check and not starting
a new thread, the running flag might have changed As a result we do not start a new thread where one
was necessary.
→ solve this by locking the queue and the running flag at the same time.
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Missed Activation (I)
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Missed Activation (II) The proxy only accesses the running state
when the queue is locked The task implementation dealt with the last
message, the queue is empty, the task is still running and is going to check whether it should continue.
A new incoming message is pushed onto the queue through a lock off the running flag and the queue. An activation does not take place.
The task implementation now locks the running flag and sets it to zero.
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Possible solutions Before finishing the task message handler, check the
queue once more Leads to unnecessary message handling if a particular task did
not choose to handle the message right now Only access the running flag after locking the queue
Links task execution and proxy access to strongly. Can lead to starvation of the task under heavy load Can lead to slowdown of external tasks that become slow in
pushing elements Work with two queues: one with messages that are being
handled, and one with incoming messages Decouples pushing and handling Groups multiple incoming requests in merely a pointer swap Allows the message handler to inspect and deal with messages
in a non sequential manner.
Activ
e M
essag
e Q
ueu
es
© Van Belle Werner - Jan2010
Working Runtime Two queues
Incoming queue Handling queue
Distinct locks on queue 'active', 'changed'
Each task has its scheduler A message handler
that transfers messages from incoming to handling that deals with the messages to be handled
Smart pointers to const messages with threadsafe reference counting.
Initiation and Termination logic A first class task to track activity of other tasks.