How to use libpointer inside parfor loop?

15 views (last 30 days)
Roman
Roman on 10 Jan 2022
Edited: Edric Ellis on 14 Jan 2022
Hello,
i have a problem with libpointer and parfor loops. I want to access several USB cable(same time) with callib(read/write) but i need libpointer for them.
If i try to open the channel and init the channel before parfor loop, i cant use the libpointer inside because they disappear.
Is there any way to access libpointer inside parfor loop without to open/init/close the whole usb channel each time ?
% here some description
%open the channel and save the pointer under pChannelHandleArr
calllib(Libname,'SPI_OpenChannel',i-1,pChannelHandleArr{i,1});
% init the channel with given pChannelHandle
calllib(Libname,'SPI_InitChannel',pChannelHandleArr{i,1},ChConfig);
%transfer data to USB or read USB(SPI_Read) with given pChannelHandle
calllib(Libname,'SPI_Write',pChannelHandleArr{i,1},DataToWrite,size(DataToWrite,2),pNumBytesTransferredArr{i,1},transfer_options);
%clse channel with given handleArr
status=calllib(Libname,'SPI_CloseChannel',pChannelHandleArr{i,1});
if my communication is every 500ms then i need to do this all again.
here is a small example of libpointer and my problem
fprintf(' before loop');
%create var as libpointer
pNumchannels = libpointer('uint32Ptr',255);
fprintf(' LOOP BEGINN');
parfor i=1:3
%the var pNumchannels is empty here, the pointer is not there anymore
pNumchannels
end
fprintf(' endBEGINN');
is there any way to open the channel, save the pointer var and use it inside parfor loops?
best Regards,
Roman

Answers (1)

Edric Ellis
Edric Ellis on 11 Jan 2022
I think you should be able to do this using parallel.pool.Constant. I think you might need 2 of them in fact - one to manage the channel, and one for the libpointer. Something a little bit like this:
chanConst = parallel.pool.Constant(@setupChannel, @teardownChannel);
ptrConst = parallel.pool.Constant(@() libpointer('uint32Ptr',255));
parfor i = 1:N
% use ptrConst.Value
end
% Function to setup the channel. This must return a value. You will need to
% deal with the arguments to `calllib` somehow...
function v = setupChannel()
% Stuff like this
calllib(Libname,'SPI_OpenChannel',i-1,pChannelHandleArr{i,1});
% I don't think you need an actual value?
v = [];
end
% Function to tear down the channel. This gets the value returned by
% setupChannel
function teardownChannel(v)
calllib(Libname,'SPI_CloseChannel',pChannelHandleArr{i,1});
end
  3 Comments
Edric Ellis
Edric Ellis on 14 Jan 2022
Remember that each worker is a separate process, and so the libpointer instances you create in each process are completely unconnected from each other. parallel.pool.Constant here is simply a way to let you create a libpointer on each worker.
I think it would help if you can separate out the setup and cleanup phases that each worker process needs to perform from the independent pieces in the body of the parfor. Here's a concrete example, adapted from the doc example for libpointer. I hope this makes some sense. (I've made use of parfevalOnAll here for setup and cleanup since there is no "object" I need to track that represents the library)
%% Create a pool if required and available
if isempty(gcp('nocreate')) && canUseParallelPool
parpool('local',3);
end
%% Load the library on each worker
% Note using fetchOutputs here only to check for errors. The function
% 'doLoadLibrary' performs all necessary setup steps that must be performed
% on each worker
fetchOutputs(parfevalOnAll(@doLoadLibrary, 0));
%% Create a libpointer on each worker
% Each worker will allocate a doublePtr with value 1.0.
xConst = parallel.pool.Constant(@() libpointer('doublePtr', 1.0));
%% Use a parfor loop to modify the value in xConst
% In this case, the value inside xConst isn't actually "Constant" - it has
% "handle" semantics, so we can modify the underlying value.
parfor ii = 1:10
% Each worker has a separate xConst.Value
myPtr = xConst.Value;
% Set the value stored in the pointer to be the loop index
myPtr.Value = ii;
% Call into the shared library to perform the operation
calllib('shrlibsample','multDoubleRef', myPtr);
% Return this worker's current value
out(ii) = myPtr.Value;
end
disp(out)
5 10 15 20 25 30 35 40 45 50
%% Cleanup - unload the library on each worker
fetchOutputs(parfevalOnAll(@unloadlibrary, 0, 'shrlibsample'))
%% Function to load the library on the workers
function doLoadLibrary()
if ~libisloaded('shrlibsample')
addpath(fullfile(matlabroot,'extern','examples','shrlib'))
loadlibrary('shrlibsample')
end
end

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!