Is this a race condition in matlab? - matlab

The title says it all. I was wondering if the following code is prone to a race condition.
classdef Foo < handle
properties
value = true
end
methods
function toggle(o, ~, ~)
o.value = ~o.value;
end
end
end
function main
foo = Foo;
uicontrol('style', 'pushbutton', 'callback',#foo.toggle);
drawnow
%// Endless loop which gets broken up by a button press
while foo.value
pause(1)
end
%// What happens if I press the button twice, really fast? There
%// is no external function called between here and the previous
%// while loop.
if foo.value
error('Race')
else
fprintf('\nWe made it\n')
end
Am I save from the race condition since everything happens in the event dispatch thread? Is the same still true if I play with Interruptible and BusyAction property of the button? I found the matlab help quite confusing.
In case it matters I'm using R2012a.

Related

Matlab-GUI warning when using parfeval(): "Unable to save App Designer app object."

I am trying to call parallel functions within my Matlab-GUI by pushing a startbutton.
For the beginning I tried to call one single function ("ReadTwinCAT") but I'm always getting the following error-message:
"Warning: Unable to save App Designer app object. Save not supported
for matlab.apps.AppBase objects."
As I thought I already used parallel functions like this within a GUI, I don't know what I am doing wrong...
Matlab-App-Designer Code:
properties (Access = private)
running_state = 0; % Description
tcClient;
db_conn;
end
methods (Access = private)
function ReadTwinCAT(app)
while app.running_state == 1
disp('running')
pause(0.1)
end
disp('stopped')
end
end
% Callbacks that handle component events
methods (Access = private)
function StartButtonPushed(app, event)
app.running_state = 1;
pool = gcp(); %Initialize pool of workers
parfeval(pool, #ReadTwinCAT, 0, app); %Call parallel function
end
end
Ok, I think I found an answer from Mathworks staff:
https://www.mathworks.com/matlabcentral/answers/366576-will-there-be-a-support-of-the-parallel-toolbox-in-matlab-app-designer#comment_720548
Note the limitation of accessing the app object inside the parfor loop or any other functions called though Parallel Computing Toolbox.
If you need to access properties of your app pass them down as values directly, e.g. instead of
b = [0,0];
parfor i=1:2
b(i) = app.myprop*2
end
use
tmp = app.myprop;
b = [0,0];
parfor i=1:2
b(i) = tmp*2
end
So it seems that you can't access (or it would seem set) the properties of the app object within a parallelized function. If you want to get data out, you'll probably have to set up a communication system using parallel.pool.DataQueue. Your example is tough to parallelize. A better option would probably be to add a listener to your running_state property, and/or use a timer function.
The major downside of this is that the function you call from the timer is not actually parallelized - it runs in the same thread, so if you have a lot of computation in ReadTwinCAT, I think it will cause lag/unresponsiveness in the GUI.
I've modified your code to use a timer instead of parfeval:
properties (Access = private)
running_state = 0; % Description
runningTimer;
tcClient;
db_conn;
end
methods (Access = private)
function ReadTwinCAT(app, varargin)
if app.running_state == 1
disp('running')
else
stop(app.runningTimer);
disp('stopped')
end
end
end
% Callbacks that handle component events
methods (Access = private)
function StartButtonPushed(app, event)
app.running_state = 1;
app.runningTimer = timer;
app.runningTimer.Period = 0.1;
app.runningTimer.ExecutionMode = 'fixedRate';
app.runningTimer.TimerFcn = #app.ReadTwinCAT;
start(app.runningTimer)
end
end
I'll share my half-baked solution here for parfor and app. If you get your function outside of App Designer you can do the following
function ExternalFunction(app)
dataQueueUpdateUI = parallel.pool.DataQueue;
afterEach(dataQueuePorthole, #UpdateUI);
parfor i = 1 : 4
CalculatingFunction(arg1, dataQueueUpdateUI)
send(dataQueueUpdateUI, 'whatever')
end
end
UpdateUI can take only one argument (cell, array, struct etc.), but based on type, you can trigger different actiens in app. The function is evaluated on client, therefore it can find app handles. You can also have multiple DataQueue objects, but I can't really tell how does it affect the lag. Speaking of it, there might be some, anything from 0-5 seconds, at least in my case.
Example for UpdateUI function, I run it every 0.5 s while I have few instances of other programs working in background. Within UpdateUI, you can do whatever you want to with the app.
function UpdateUI(arg)
% Initialising app
persistent app
if isempty(app)
app = get(findall(0, 'type', 'figure'), 'RunningAppInstance'); % if you only have one figure on
end
pause(0.1)
drawnow limitrate;
end

Matlab stop function's execution

I have an array. I am processing elements of this array in a for loop inside a function.
function results = processArray(array)
for ii = 1:length(array)
%some stuff here
results(ii) = %getting the results for this particular element
end
end
There might be a lot of elements and computations might take a lot of time. I want to be able to finish execution of the for loop at any arbitrary time when a user wants to do that so that the results for already processed elements would be available.
I was trying to make a figure with a button which would change a boolean flag. Inside the for loop I was checking the value of that boolean. If the boolean changed then the for loop should break.
function results = processArray(array)
fig = figure;
fig.UserData.continue = 1;
uicontrol('Parent', fig', 'Style', 'pushbutton', 'String', 'stop', 'callback', #interrupt)
for ii = 1:length(array)
if(fig.UserData.continue == 0)
break;
end
%some stuff here
results(ii) = %getting the results for this particular element
end
end
function interrupt(obj, ~)
fig = obj.Parent;
fig.UserData.continue = 0;
end
well, that does not work. The figure shows up only after all the computations are done already. If I draw the figure first using something like waitforbuttonpress and proceed to the for loop pressing the button does not stop the execution. I think the callback function is being executed only after the for loop is finished. Is there any way to solve this?
You will need to drawnow after you create the button, so it will show up. You also need to drawnow within the loop to update the button state. Then you should achieve what you want.
drawnow force figure update, so it will slow down your computation a little.

How do I alter a variable with a uicontrol callback function?

The big picture goal is to successively plot an image sequence at some rate and pause the process when the pushbutton is pressed. Then resume the process upon hitting the space bar or pressing the pushbutton or whatever. Here is the code I have so far with a simple rand/pause(0.5) procedure for each iteration of the loop (instead of plotting my images).
My issue is this:
ButtonCallback seems to be invoked when the pushbutton is pressed, and DoPause is set to 1 in the callback function, BUT DoPause is not changed in the main function PauseButtonTest. How do I change this variable so the if statement in my while loop is executed.
Any help is appreciated. Thanks.
function PauseButtonTest
DoPause = 0;
hb = uicontrol('Style','Pushbutton','String','Pause','FontWeight','Bold', ...
'Callback',#ButtonCallback,'Unit','Normalized','Position',[0 0 1 1]);
while ishandle(hb)
if DoPause
disp('You pushed the button')
pause
DoPause = 0;
set(hb,'Enable','On')
drawnow
end
% Computations/Plot successive figures/etc.
rand
pause(0.5)
end
end
function ButtonCallback(hObj, event)
DoPause = 1;
disp('You are in ButtonCallback')
disp(['DoPause = ' num2str(DoPause)])
set(hObj,'Enable','off')
end
Nested functions.
Just move function ButtonCallback(hObj, event) ... inside PauseButtonTest so that it has access to its variables ("externally scoped" variables). Plop it down a couple of lines below the while loop and before the end that signals the end of PauseButtonTest.

creating handles in a for loop

I'm creating a GUI with a large number of checkboxes
h.f = figure('units','pixels','position',[200,200,150,50],...
'toolbar','none','menu','none');
for i=1:100
num_data=round((100*(5*rand()))/100);
end
h.t(i) = uicontrol('style','text','units','pixels',...
'position',[30,820-15.*i,150,15],'string','za');
h.c.a(i) = uicontrol('style','checkbox','units','pixels',...
'position',[150,820-15.*i,125,15],'string','1');
if num_data>1
h.c.b(i) = uicontrol('style','checkbox','units','pixels',...
'position',[175,820-15.*i,25,15],'string','2');
end
if num_data>2
h.c.c(i) = uicontrol('style','checkbox','units','pixels',...
'position',[200,820-15.*i,25,15],'string','3');
end
if num_data>3
h.c.d(i) = uicontrol('style','checkbox','units','pixels',...
'position',[225,820-15.*i,25,15],'string','4');
end
if num_data>4
h.c.e(i) = uicontrol('style','checkbox','units','pixels',...
'position',[250,820-15.*i,25,15],'string','5');
end
h.p = uicontrol('style','pushbutton','units','pixels',...
'position',[40,5,70,20],'string','OK',...
'callback',#p_call);
% Pushbutton callback
function p_call(varargin)
vals=get(h.c, 'Value');
checked = find([vals{:}]);
if isempty(checked)
checked = 'none';
disp(checked)
else
for i=checked
Data1=dlmread(strcat(files{i}, ' PYRO.txt'),2,0);
plot(Data1(3:end,1),Data1(3:end,2))
hold on
end
end
hold off
The code is placing the checkboxes in the right place, but h is disappearing at the end of the for loop, and this is the error I'm getting.
??? Undefined variable "h" or class "h.c".
Error in ==> checkboxesGUI>p_call at 50
vals=get(h.c, 'Value');
??? Error while evaluating uicontrol Callback
How do I make it so I can call back on h?
The error indicates that p_call does not have access to the struct h where your handles are stored. Your entire code is not posted, but it seems clear that p_call is not nested in the function that owns h. Restructure your code so p_call has access to h, or pass h as an input argument every time it is called.
Also, a problem is that h.c is a struct, not a handle. Your handles are in the subfields of h.c (i.e. h.c.a, h.c.b, etc.). This is a bit messy, so I would suggest changing the code so you keep the checkbox handles in an array addressed via h.c(i) so your get and find lines will work.

MATLAB: exiting infinite loop without using global variable in GUI

Background: I have several portion in an GUI to handle different tasks. In 1 portion (portion1) I have text input and send button. So once I will click send it would send one data to my serial port. Another portion (portion2) would receive signal from serial port which have been received from other devices. Both the portions are using two buttons; one to start the work of that particular portion and one to stop the work. I have used global variables and while loop (with boolean) to exit the infinite loop, as I need to send the data or receive data continuously.
My question: Problem is when I am using global variables and the above mentioned way of using infinite loop, if I click portion1, portion1 will start iterate. Now if I click portion2 then portion1 will be stopped. But I need to use them both at the same time and both of them will continuously send and receive data until I click other button (s) to exit the infinite loop.
My sample code for clarification:
function send_Callback(hObject, eventdata, handles)
global firstFlag;
firstFlag = true;
while firstFlag
%Required codes
end
function haltSend_Callback(hObject, eventdata, handles)
global firstFlag;
firstFlag = false;
function receive_Callback(hObject, eventdata, handles)
global secondFlag;
secondFlag = true;
while true
%Required codes
end
function stopReceive_Callback(hObject, eventdata, handles)
global secondFlag;
secondFlag=false;
I have tried to find a solution referring to internet, but most of the solutions are using global variable. It would be better if I could work without global variables. But even if my requirements are fulfilled (as per my question) it would work.
Global or not is not the issue here.
Callbacks in Matlab all run on the same thread.
So when callback1 is running and you trigger callback2, callback2 will interrupt callback1.
callback1 will then only proceed once callback2 is finished.
You can only slightly modify this procedure using the BusyAction property:
http://www.mathworks.de/de/help/matlab/ref/uicontrol_props.html#bqxoija
But this won't help in your case.
In a "proper" programming language, you'd have a sending and a receiving thread running in parallel. You can't do this matlab however - unless you're e.g. willing to write java-code.
If you want to stick with matlab, the closest to thread would be timers.
These would replace your while loops.
E.g. as in the following minimalistic example:
function cbtest()
try close('cbtest');end
f = figure('name', 'cbtest');
% create the timers:
period = 0.2; % period in seconds, in which the timer shall execute
sendTimer = timer('TimerFcn', #sendFcn, 'ExecutionMode', 'fixedDelay', 'Period', period, 'TasksToExecute', Inf);
recvTimer = timer('TimerFcn', #recvFcn, 'ExecutionMode', 'fixedDelay', 'Period', period, 'TasksToExecute', Inf);
uicontrol(f, 'position', [10 10 100 25], 'Callback', #(a,b) start(sendTimer), 'string', 'start1');
uicontrol(f, 'position', [120 10 100 25], 'Callback', #(a,b) stop(sendTimer), 'string', 'stop1');
uicontrol(f, 'position', [10 50 100 25], 'Callback', #(a,b) start(recvTimer), 'string', 'start2');
uicontrol(f, 'position', [120 50 100 25], 'Callback', #(a,b) stop(recvTimer), 'string', 'stop2');
end
function sendFcn(hTimer, timerEvt)
% your send-loop-code
disp('sending');
end
function recvFcn(hTimer, timerEvt)
% your receive-loop-code
disp('receiving');
end
sendFcn and recvFcn here then should contain the code you have within your according while loops.
You can of course lower the period to your needs, I chose the above for testing purposes.
Your problem is that you're executing the loop inside the Callbacks. So when the second button is clicked, the second callback will start and loop infinitely, until it is ended. The first loop will wait for the second Callback to terminate until it can resume. What you need is a main program where you execute your loop. Nesting the Callbacks will make sure they can access and change the local variables without making them global. If you're fine with building a GUI programmatically, try this:
function main()
sendFlag = false;
receiveFlag = false;
while true
if sendFlag
% Your Sending code
end
if receiveFlag
% Your Receiving code
end
end
function send_Callback(~,~,~)
sendFlag = true;
end
% other Callbacks
end
Then in the Callbacks for your Buttons (you could use Toggle Buttons by the way), you simply set the sendFlag and receiveFlag, respectively.
Using GUIDE, you want to use toggle buttons.
I don't exactly know how GUIDE handles the OpeningFcn, so you should probably put a "Start" button into your GUI which basically executes the above program with a few changes:
function startbutton_Callback(hObject,~,handles)
while true
handles = guidata(hObject); % Updates handles structure
sendFlag = get(handles.sendtoggle, 'Value');
if sendFlag
% Your Sending code
end
receiveFlag = get(handles.receivetoggle, 'Value');
if receiveFlag
% Your Receiving code
end
end
Also, create send and receive toggle buttons and set their 'Min' to 0 and 'Max' to 1. This will make them switch their 'Value' property (which you read in the above loop) between 0 and 1 when you click them. In the Callback, you can change what they display:
function send_Callback(hObject,~,handles)
on = get(hObject,'Value');
if on
set(hObject, 'String', 'Stop sending');
else
set(hObject, 'String', 'Start sending');
end
guidata(hObject,handles); % Update GUI data
Now your main function, which starts when you click the start button, runs the loop and just checks the toggle buttons' states to determine whether to send and receive.