You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How to start and stop parallel Timer Delays (on / off delays) in Matlab
6 views (last 30 days)
Show older comments
Hi everyone. I am trying to write a code in matlab for the on delay and off delay for several parallel events.
Each event on its own should be represented as shown in the picture attached:
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/254531/image.png)
The code sould be written in matalb and should also be supported for C/C++ Code Generation.
The idea is to write a function which can be called by several events in parallel. I am not using any additional toolboxs for the moment to create this solution.
So far I have written this function which is not working as expected:
Thanks in advance for your help.
function Q=TimeDelay(IN,PT)
t = timer('TimerFcn', 'Q=true','StartDelay',PT);
switch IN
case 1
Q=false;
start(t)
while(Q==false)
disp(Q)
pause(1)
end
stop(t)
%delete timer objects after using
delete(t)
case 0
stop(t)
%delete timer objects after using
delete(t)
Q=false;
end
end
Answers (1)
Walter Roberson
on 17 Dec 2019
The code sould be written in matalb and should also be supported for C/C++ Code Generation.
The idea is to write a function which can be called by several events in parallel.
You have no hope of achieving your aims with MATLAB. Timers are not supported for code generation, and Parallel Computing Toolbox is not supported for code generation.
18 Comments
Walter Roberson
on 17 Dec 2019
C++ does not have these kinds of timers, but there are some implementing libraries such as https://www.fluentcpp.com/2018/12/28/timer-cpp/
Walter Roberson
on 17 Dec 2019
If you do not use a library such as the one above that uses threads such as std::thread for C++11 or later, then the general technique is to construct a time-sorted queue of actions each with an associated firing time. Then at any given step, the software looks at the head of the queue and if the associated time has been reached then execute the associated action; if not then sleep for a relative time approximately equal to the difference between the target time and the current time. The associated action could, with some care, include queueing new actions.
This works provided that the associated actions do not hog the foreground control. For example you would not have the action make a loop pausing for a second and displaying something, not unless you were sure that the loop would terminate before the next queued action. Instead you would do an iteration to the point where the pause would be, and then queue a "continuance" that would pick up where you left off.
As it is not possible in C/C++ to create a pointer to an arbitrary position in the code to resume at (no pointers to the machine instruction level) you would need probably need one of the techniques for building a State Machine. For State Machines you either push each fragment into a separate function (because it is permitted to store function pointers), or else you create state variables and have your code test each time what the current state is:
switch (state) {
case 1:
iter = 0;
state = 2;
break;
case 2:
if (iter++<10) {
printf('present!\n') ;
}
else {
state = 3;
}
etc
} ;
Bab
on 17 Dec 2019
Thanks Walter for your reply.
I am developing currently only in matlab and simulink environment with no additional toolboxes. Then convert the code to C and dont touch that code anymore.
It would be really benefitial to finde a solution within matlab for such parallel time driven events, since this is my major development environment.
My first approach would be to realise this simple logic for parallel tasks:
- Set the condition "waitingDone" to "True" after "some time" has elapsed
But I dont want my whole application to be in pause during waiting time. There are many other important tasks that have to run in parallel.
As you mentioned here:
"then the general technique is to construct a time-sorted queue of actions each with an associated firing time. Then at any given step, the software looks at the head of the queue and if the associated time has been reached then execute the associated action; if not then sleep for a relative time approximately equal to the difference between the target time and the current time. The associated action could, with some care, include queueing new actions"
Do you have a short demo how the implementation would look like?
Best,
B
Walter Roberson
on 17 Dec 2019
no additional toolboxes
parallel time driven events
Even before conversion to C/C++, you cannot meet your goals inside MATLAB, not without the Parallel Computing Toolbox. You are trying to fire parallel events that do work whose duration exceeds the time before firing the next event. That is not possible in MATLAB without Parallel Computing Toolbox.
Timers keep running while MATLAB is processing code, and when a timer is ready to fire, the timer is given control at the beginning of the next line of MATLAB code (that is, the logic that checks for timers ready is invoked at the beginning of each physical line of MATLAB code, not at the beginning of each sub-expression, and not at each semi-colon.
A; B; C;
D;
timer activity will be checked before executing A and before executing D, but not before executing B or C.
Now, if B or C happen to be MATLAB functions themselves, then they contain multiple lines of code, and the timer can fire at the beginning of any of those lines. But the timer would not fire during an external library call for example, and not while heavy computation that was deligated to LAPACK or MKL is executing.
Although multiple timers can exist and can fire independently, MATLAB is single threaded, and the current timer takes over that thread: the MATLAB code being executed is suspended while the timer callback executes, and further timers cannot fire until the first one returns. If your timer callback has a sleep/disp loop, then no other timers can get control until the first timer is finished.
Unfortunately, that is exactly what you are trying to do. You are trying to create multiple independent MATLAB threads that all run simultaneously without cooperation between them . The only way to do that in MATLAB is Parallel Computing Toolbox, in which case each "worker" is a separate MATLAB process with its own interpreter and threads. Communication between the workers, or between the workers and the client, are relatively limited but possible in some situations. The workers do not share memory with each other or the client.
To get any further without rewriting your tasks into C++ code, you need to rewrite the tasks to be co-operative -- to do only the most immediate work and then to give up control to wait for the next event, such as by writing a state machine.
It is 3am where I am, and writing a good state machine to handle multiple independent events takes a bunch of work, so I will postpone that for now.
Bab
on 17 Dec 2019
Oh I see its pretty late. So many thank for the moment and have a good night!
For the moment you would say, there is no solution in matlab? I wonder how to solve any control problems, in which many parallel time driven events can occure in matlab?
It would be great to catch up later!
Best
B
Bab
on 18 Dec 2019
Dear Walter,
did you had the chance to think about a state machine solution for this problem?
I am very curious to see your idea here, since I am still searching for solution of this problem.
Many thanks,
B
Bab
on 20 Dec 2019
Ok no worries.
It would just be a great help to understand the solution option with State Machines in an example.
Walter Roberson
on 22 Dec 2019
Edited: Walter Roberson
on 23 Dec 2019
Create an array of information about pending events (e.g., cell array or struct array). Each event should have an absolute start time attached to it.
loop:
Peak into the array to find the start time of the first entry, and calculate the time difference relative to now. If there are no pending events, queue an event at the default delay (e.g., you might want to check for external events every 30 seconds anyhow) with the queued event configured to do whatever long-term processing is desired.
If the time to the first event is positive, sleep that long.
At this point, either the first event was already scheduled in the past, or just happened to be right for the present when checked (unlikely but possible), or else you just slept and woke up to process the event that was in the future. In all of these cases, dequeue the first event and examine it.
Besides the start time, each queue entry should have a state vector, and should have the handle to an anonymous function.
Invoke the anonymous function, passing in the state vector, and the current time, and the time that the event was scheduled to run. Have the anonymous function return two values: an updated state vector, and the absolute time that it should run again. The anonymous function should never deliberately sleep for more than a very small time (e.g., pause of 0.01 to allow graphics objects to update might be justifiable, but not a pause of 1 second.)
If the absolute time returned to run again is empty, do not queue an event as a result; drop the state vector and the anonymous function information (that is, the function determined there was nothing more to do.)
If the absolute time returned to run again is not empty, queue a new event with the same anonymous function and with the returned state vector and with the absolute time given. For fairness, queue it after any other event with the same or earlier absolute time. (You could consider creating a queue priority scheme.)
Now loop back.
Note that if there were several events queued for a time and that time has been reached, then this algorithm will not deliberately delay in-between executing them: any delay will only be in overhead and in time spent serving other events.
The anonymous functions should be constructed to not delay; if they have some reason to delay, then they should instead store state information into the state vector and return the state vector and the time to wake up.
count = 0;
for K = 1 : 10
fprintf('first round #%d\n', K);
count = count + 1;
pause(1);
end
for K = 1 : 5
fprintf('second round #%d\n', K);
count = count + 1;
pause(2);
end
fprintf('final count: %d\n', count);
could be rewritten like
majorstate = statevector(1);
minorstate = statevector(2);
count = statevector(3);
if isnan(majorstate) %convention, nan for initialization
majorstate = 1;
minorstate = nan;
count = 0;
end
if majorstate == 1
if isnan(minorstate)
minorstate = 1;
end
if minorstate > 10
majorstate = 2;
minorstate = nan;
nextime = now;
else
fprintf('first round #%d\n', minorstate);
minorstate = minorstate + 1;
count = count + 1;
nexttime = now + seconds(1);
end
elseif majorstate == 2
if isnan(minorstate)
minorstate = 1;
end
if minorstate > 5
majorstate = 3;
minorstate = nan;
nexttime = now;
else
fprintf('second round #%d\n', minorstate);
minorstate = minorstate + 1;
count = count + 1;
nexttime = now + seconds(2);
end
else %majorstate 3
fprintf('final count: %d\n', count);
majorstate = 4;
minorstate = nan;
nexttime = []; %all used up
end
statevector(1) = majorstate;
statevector(2) = minorstate;
statevector(3) = count;
You can acheive slight efficiencies by doing thins like initializing minorstate to the first value needed by the next state, instead of initializing to nan and then testing isnan() to initialize. However, separating them like I did gives more separation of functionality; for example if you wanted the second loop to count from 50 to 200 by 17's, then the code for the first state would not need to know to initialize to 50, and so it becomes easier to rewrite the code in sections.
Bab
on 23 Dec 2019
Thank you Walter!
That looks like an interesting approach. So I created this function as bellow.
But would you use or invoke this function now? Here I was not successfull yet:
('Invoke the anonymous function, passing in the state vector, and the current time, and the time that the event was scheduled to run. Have the anonymous function return two values: an updated state vector, and the absolute time that it should run again')
function statevector=PendingEvents_AnonymusFunction(statevector)
majorstate = statevector(1);
minorstate = statevector(2);
count = statevector(3);
if isnan(majorstate) %convention, nan for initialization
majorstate = 1;
minorstate = nan;
count = 0;
end
if majorstate == 1
if isnan(minorstate)
minorstate = 1;
end
if minorstate > 10
majorstate = 2;
minorstate = nan;
nextime = now;
else
fprintf('first round #%d\n', minorstate);
minorstate = minorstate + 1;
count = count + 1;
nexttime = now + seconds(1);
end
elseif majorstate == 2
if isnan(minorstate)
minorstate = 1;
end
if minorstate > 5
majorstate = 3;
minorstate = nan;
nexttime = now;
else
fprintf('second round #%d\n', minorstate);
minorstate = minorstate + 1;
count = count + 1;
nexttime = now + seconds(2);
end
else %majorstate 3
fprintf('final count: %d\n', count);
majorstate = 3;
minorstate = nan;
nexttime = []; %all used up
end
statevector(1) = majorstate;
statevector(2) = minorstate;
statevector(3) = count;
end
Walter Roberson
on 23 Dec 2019
function [statevector, nexttime] = PendingEvents_AnonymusFunction(statevector)
and
event1 = {now, @PendingEvents_AnonymusFunction, nan(1,3)};
eventqueue = {event1};
then the logic I described, which would have code such as
current_event = eventqueue{1};
eventqueue(1) = []; %dequeue it
[newstatevector, nexttime] = current_event{2}(current_event{3});
current_event{1} = nexttime;
current_event{3} = newstatevector;
if !isempty(nexttime)
eventqueue = queue_event(eventqueue, current_event);
end
queue_event would be responsible for placing current_event into the event information array in sorted order by time.
Bab
on 23 Dec 2019
Is queue_event an internal function of matlab or a self writen function?
How would queue_event look like?
Sorry for asking but I think I am missing the overview of all related functions unfortunatley.
Currently I have:
function [statevector, nexttime] = PendingEvents_AnonymusFunction(statevector)
which is respobsible for statebvector definition and nexttime.
and queue_event for placing current_event into the event information array in sorted order by time
But how would the logic look like if I have for example two on delay timers with logic shown below. With IN as input signal, ET as elapsed time and Q as output signal showing the time is elapsed and IN is still true? The two on delay timers would have different ET of course.
Many Thanks
![TON.png](https://www.mathworks.com/matlabcentral/answers/uploaded_files/256831/TON.png)
Walter Roberson
on 24 Dec 2019
function eventqueue = queue_event(eventqueue, current_event)
if isempty(eventqueue)
eventqueue = {current_event};
else
event_times = cellfun(@(C) C{1}, eventqueue);
this_event_time = current_event{1};
before_idx = find(event_times > this_event_time, 1, 'first');
eventqueue = [eventqueue(1:before_idx-1), {current_event}, eventqueue(before_idx:end)];
end
Walter Roberson
on 24 Dec 2019
But how would the logic look like if I have for example two on delay timers
You would create one anonymous function for each different shape. If you had two waves with the same shape structure but slightly different timings, then you could encode the different timings into the statevector but call the same anonymous function.
Each anonymous function would not need to know that the other function even exists. But!! each anonymous function must give up control after generating each sample.
There are different ways you can handle continuous sample output. One way is to call the anonymous function for each event on a per-sample basis even when the output is not changing. Another way is to declare an implicit "sample and hold" -- that each time through, if it is not time for an event function to run yet, then the previous value associated with the channel should be copied. A third way is to associate a delta value with each channel, and when it is not time for the event function to run yet, then add the delta to the previous value in order to determine the new value. (You could, of course, have a delta of 0 in order to maintain the current value.)
The general structure I described before can easily be modified to add a channel number to the state description, and you can adopt a convention such as that the first element of the output state vector is to become the new channel output (and if you use delta values, that the second output is to become the delta.) For events whose channel number is out of range, just don't output anything -- this would permit events which are not associated with a signal (such as the demonstration involving displaying text to the console.)
Bab
on 24 Dec 2019
Thank you Walter.
So far I have created three functions as follows:
I think I am more a person who understand through examples. So here my questions are: what exactly are minor and major states? and why there are the limits 5 and 10 for the minor states?
an example would be great for me to understand I guess. and maybe the function could be made more generic so that the limits 5 and 10 are inputs. But to do that I need to understand this function better.
function [statevector, nexttime] = PendingEvents_AnonymusFunction(statevector)
majorstate = statevector(1);
minorstate = statevector(2);
count = statevector(3);
if isnan(majorstate) %convention, nan for initialization
majorstate = 1;
minorstate = nan;
count = 0;
end
if majorstate == 1
if isnan(minorstate)
minorstate = 1;
end
if minorstate > 10
majorstate = 2;
minorstate = nan;
nextime = now;
else
fprintf('first round #%d\n', minorstate);
minorstate = minorstate + 1;
count = count + 1;
nexttime = now + seconds(1);
end
elseif majorstate == 2
if isnan(minorstate)
minorstate = 1;
end
if minorstate > 5
majorstate = 3;
minorstate = nan;
nexttime = now;
else
fprintf('second round #%d\n', minorstate);
minorstate = minorstate + 1;
count = count + 1;
nexttime = now + seconds(2);
end
else %majorstate 3
fprintf('final count: %d\n', count);
majorstate = 3;
minorstate = nan;
nexttime = []; %all used up
end
statevector(1) = majorstate;
statevector(2) = minorstate;
statevector(3) = count;
end
for calling I made this .m file, but to be honest, I am not understanding this calling as well. Here we create an event first rigth? but why we give a nan vector to our function?
How would two parallel events look like? (for example we have one active event with delay of 1 min, and we activate another one with the delay of 2 min?
I think the complexity increased a bit, so that I lost the connections between the functions but I think once I have an example, I will easily get the idea.
event1 = {now, @PendingEvents_AnonymusFunction, nan(1,3)};
eventqueue = {event1};
current_event = eventqueue{1};
eventqueue(1) = []; %dequeue it
[newstatevector, nexttime] = current_event{2}(current_event{3});
current_event{1} = nexttime;
current_event{3} = newstatevector;
if ~isempty(nexttime)
eventqueue = queue_event(eventqueue, current_event);
end
and for queue_event as you suggested:
function eventqueue = queue_event(eventqueue, current_event)
if isempty(eventqueue)
eventqueue = {current_event};
else
event_times = cellfun(@(C) C{1}, eventqueue);
this_event_time = current_event{1};
before_idx = find(event_times > this_event_time, 1, 'first');
eventqueue = [eventqueue(1:before_idx-1), {current_event}, eventqueue(before_idx:end)];
end
end
Walter Roberson
on 24 Dec 2019
Refer back to the example I gave:
count = 0;
for K = 1 : 10
fprintf('first round #%d\n', K);
count = count + 1;
pause(1);
end
for K = 1 : 5
fprintf('second round #%d\n', K);
count = count + 1;
pause(2);
end
fprintf('final count: %d\n', count);
the 10 that is the upper bound of the first loop becomes the limit of 10 for majorstate 1, and the 5 that is the upper bound for the second loop becomes the limit of 5 for majorstate 2.
The 10 was pulled out from your originally posted code that looped displaying values and pausing in-between. The 5 was pulled out "from thin air" in order for me to illustrate that the state machine approach does not need to use the same limits for each loop.
When you write state machines, it would be possible to number all of the states consecutively, and use only one state counter, but if you do that then it becomes a nuisance to edit the code (you end up renumbering states a lot.) It is usually easier to give a "major" state number to each outer block of code, and then use increasingly many states to designate further nested blocks. In the above example, there is an initialization phase (which I put into state 0), then the 1:10 block is the first important block so I assigned it a major state of 1 and the second important block a major state of 2; those two were each for loops, which need a state variable corresponding to the current value of the loop control variable. If there had been a nested loop, a third state would have been necessary.
That said, you really only need a state variable for any information you need to preserve while you give up control; if you were to take the same code as above but remove the pause(2) so that there was no waiting needed there, then you could just run that entire block and the "final count" final block all together as soon as the code detected that it was finished with the first for loop.
You need as many state entries as the maximum length of temporary information that you need to preserve while you give up control. However, as temporary variables go into and out of existence, keeping track of the minimum length needed right now and marshalling the values into and out of that minimum length, gets to be a nuisance. What is usually easier instead is to reserve a state entry for each variable that needs to be preserved at some point, without worrying too much about whether you could get away without perserving it this time. (Though at the same time, a practice of re-using variable names helps keep the number of state entries lower.)
Bab
on 25 Dec 2019
Dear Walter,
Merry christmas first of all :) Hope you enjoyed!
Unfortunatley with the code I showed you obove I am not able to move over the first round (first round #1). The original idea was to have two events one with 10 sec delay another with 5 and run them in paralle. Unfortunaley the sleep function would have stopped the other tasks in the whole application from running so it was not possible to use this.
But now I think I still miss the right way of calling or initiating events and I guess the key is to write this call function right:
event1 = {now, @PendingEvents_AnonymusFunction, nan(1,3)};
eventqueue = {event1};
current_event = eventqueue{1};
eventqueue(1) = []; %dequeue it
[newstatevector, nexttime] = current_event{2}(current_event{3});
current_event{1} = nexttime;
current_event{3} = newstatevector;
if ~isempty(nexttime)
eventqueue = queue_event(eventqueue, current_event);
end
With this call function I am not able to go over first round. There is no continuation so that I know it the delay has be elapsed or not and I can also not see how to set the second event to run in parallel.
For me it would help a lot to see in code how to run the simple two events in parallel.
Perhaps a comment for each line, what each line should do would help.
What do you think?
Thanks
See Also
Categories
Find more on Logical in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)