MATLAB中的信号量和锁

14

我正在进行一个MATLAB项目,希望有两个并行运行的MATLAB实例共享数据。我将这些实例称为MAT_1MAT_2。具体而言,系统的架构如下:

  1. MAT_1按顺序处理图像,使用imread逐个读取图像,并使用imwrite输出每个图像的结果。
  2. MAT_2使用imread读取MAT_1输出的图像,并在其他地方输出其结果。

我认为需要解决的问题之一是确保MAT_2MAT_1完全写入图像后读取图像。

我的问题是:

  1. 您会如何解决这个问题?我需要使用信号量或锁来防止竞争条件吗?
  2. MATLAB是否提供锁定文件的机制?(即类似于flock的东西,但由MATLAB直接提供,并且可以在多个平台上工作,例如Windows和Linux)。如果没有,您是否知道任何第三方库,我可以在MATLAB中使用它来构建此机制?

编辑:

  • 正如@yoda在下面指出的那样,并行计算工具箱(PCT)允许在MATLAB工作进程之间进行阻塞调用,这非常棒。尽管如此,我特别感兴趣的是不需要PCT的解决方案。
  • 为什么我需要MAT_1MAT_2在并行线程中运行:

    MAT_2处理的速度平均较慢(且更容易崩溃),而MAT_1的输出会供给其他程序和进程(包括人工检查),这些程序和进程不需要等待MAT_2完成其工作。

答案:

  • 对于允许实现信号量但不依赖于PCT的解决方案,请参见下面Jonas的答案
  • 对于该问题的其他好方法,请参见下面Yoda的答案

@DustyCampbell,我猜OP想要穷人的并行化。 - chessofnerd
6个回答

8
我会使用信号量来解决这个问题;在我的经验中,PCT在同步方面速度过慢。
dfacto(另一个答案)为MATLAB提供了很好的信号量实现,但它不能在MS Windows上工作。我对其进行了改进,以使其能够在Windows上运行。改进后的工作在这里:http://www.mathworks.com/matlabcentral/fileexchange/45504-semaphoreposixandwindows 与Java、.NET、PCT或文件锁相比,这将具有更好的性能。这不使用Parallel Computing Toolbox(PCT),而且据我所知,PCT中也没有信号量功能(他们为什么把它留出来还让人感到困惑!)。虽然可以使用PCT进行同步,但我尝试过的所有方法都非常慢。
要将此高性能信号量库安装到MATLAB中,请在MATLAB解释器中运行以下命令:mex -O -v semaphore.c
您需要安装C++编译器将semaphore.c编译为二进制MEX文件。然后,该MEX文件可从您的MATLAB代码中调用,如下例所示。
使用示例:
function Example()
    semkey=1234;
    semaphore('create',semkey,1);
    funList = {@fun,@fun,@fun};
    parfor i=1:length(funList)
        funList{i}(semkey);
    end
end
function fun(semkey)
    semaphore('wait',semkey)
    disp('hey');
    semaphore('post',semkey)
end

5

个人建议使用并行处理工具箱来完成这项任务。

据我所知,Matlab中没有直接的方法可以实现系统范围内的文件锁定。但是,为了确保当文件写入完成后,Matlab #2 才会读取 Matlab #1 的输出结果,建议在写入例如文件 results_1.mat 后,Matlab #1 写入第二个文件 results_1.finished,这是一个空文本文件。由于第二个文件是在第一个文件之后写入的,它的存在表示结果文件已经写入。因此,您可以搜索扩展名为 finished 的文件,即 dir('*.finished'),并使用 fileparts 获取您想要在 Matlab #2 中加载的 .mat 文件的名称。


谢谢@Jonas。这是个好主意,我也想过这个,但我想知道是否还有其他方法。我以前用过PCT,据我所记,这不是他们直接支持的功能;我没有看到在PCT中支持正在运行的MATLAB进程之间的信号传递的任何信息。据我所知,PCT支持的大多数内容是MATLAB函数和脚本的异步和同步执行,通常需要完全的数据或任务并行性。 - Amelio Vazquez-Reina
是的, 并行处理工具箱不能让两个Matlab会话相互通信。我可能会选择要么并行地完成所有#1和所有#2,或修改代码,使我的“parfor”循环先执行#1的一步,然后执行相应的#2。 - Jonas
谢谢@Jonas。我接受了这个答案,因为它更符合我的要求。它允许我在不使用PCT的情况下构建锁。 - Amelio Vazquez-Reina
@AmV:我只是好奇你是怎么用这个解决方案实现文件块的,因为我也可能需要使用它。另外,如果在Matlab 1仍在运行时做dir('filename'),那么没有运行的部分将会缺少文件,对吧?那么你每次都需要运行dir并检查新文件,是吗? - user564376
@doob,您可以使用MATLAB timers实现此操作。如@Jonas所建议的那样,您可以使用dir('*.finished')每隔几秒钟检查新的**.finished**文件。 - Amelio Vazquez-Reina
这种方法似乎存在风险,因为您依赖于文件系统的某些语义。如果MAT_1将文件系统中的操作顺序视为(“写入image1的最后一个字节”,“创建image1.finished”)-则不能保证MAT_2会以相同的顺序感知这些操作。 - gcbenison

3

我不确定您是否只需要matlab的解决方案,但我刚刚提交了一个信号量包装器供Matlab使用。它作为通用信号量工作,但主要是针对sharedmatrix进行设计。

只要Mathworks接受了提交,我将在我们研究小组的博客上更新链接。

请注意,这个mex文件是POSIX信号量功能的包装器。因此,它将在Linux、Unix和MacOS上工作,但不能在Windows上直接使用。当编译cygwin库时,它可能会起作用。


1

我认为除了使用特定于操作系统的锁之外,没有绝对可靠的方法。一种方法可能是让MAT_1执行以下操作:

imwrite(fileName);
movefile(fileName, completedFileName);

并且只让MAT_2处理completedFileName文件。


2
谢谢@Ashish。这是一个有趣的想法,但在Windows中移动操作是原子的吗? - Amelio Vazquez-Reina

1

编辑:

看到您的编辑后,一个不涉及使用任何工具箱的简单解决方案如下:

由于MAT_2MAT_1慢得多,因此延迟启动MAT_2。即,在MAT_1完成处理大约5张图像后再启动它。如果这样做,MAT_2将永远无法赶上MAT_1,因此永远不会出现必须从MAT_1等待图像的情况。


我仍然不清楚你问题中的一些事情:

  1. 你说MAT_1按顺序处理图像,但是它必须这样吗?换句话说,它们被处理的顺序是否重要?
  2. 你说MAT_2读取MAT_1的输出...它必须按照MAT_1完成的顺序进行吗,还是可以任意顺序?
  3. 你说MAT_2使用imread读取图像并将其输出到其他地方。有没有理由将该任务合并到MAT_1中?

无论如何,您都可以使用并行计算工具箱实现某种形式的执行阻塞;但是,您将不得不创建一个分布式作业(example),而不是使用parfor循环(这是大多数人使用的方法)。

需要注意的是,每个工人(实验室)都有一个labindex,您可以使用labSend将数据从工人1(相当于MAT_1)发送到工人2(相当于MAT_2),然后使用labReceive接收它。根据labReceive的文档:

此函数会阻止实验室的执行,直到发送实验室中发生对应的labSend调用。

这基本上就是您想要使用MAT_1MAT_2做的事情。

另一种方法是在当前会话中生成一个额外的工作进程,但仅将由MAT_1执行的任务分配给它。然后,您设置任务的{{link1:FinishedFcn}}属性以执行由MAT_2执行的函数集,但我不建议这样做,因为我认为这不是FinishedFcn的意图,并且我不知道在某些情况下是否会出现问题。


谢谢@yoda。我可能错了,但我认为上次使用PCT时,它没有像“labsend”和“labreceive”这样的东西。那肯定有帮助!至于为什么我需要MAT_1MAT_2在并行线程中运行,是因为MAT_2中的处理比MAT_1慢得多,并且MAT_1的输出馈送到其他程序和进程(包括人工检查),它们不需要等待MAT_2完成其工作。无论如何,为了澄清(我会把它放在原始帖子上),我特别感兴趣的解决方案不需要PCT许可证。 - Amelio Vazquez-Reina
@AmV:你说得对,PCT和DCT(分布式计算工具箱)曾经是不同的,但现在它们已经合并为一个了。我想我会等待你的编辑,因为更多的信息肯定会有所帮助。 - user616736
@AmV:请查看我的编辑,这是一个更简单的解决方案,不需要任何工具箱。 - user616736
labSend和labReceive最初是在R14-sp3中实现的(如果我没记错的话...)。然而,spmd关键字使事情更加方便。需要记住的一件事是 - 如果您的进程位于不同的主机上,则在文件系统更新可见之前可能会有一些延迟... - Edric

0
我还建议看一下并行处理工具箱,这样的功能应该在其中某个地方。我认为这比尝试同步两个 MATLAB 实例更加清晰(除非你被迫使用两个实例)。
在极端情况下,如果没有这样的工具,您也可以考虑不同的环境来实现您想要的功能。这可能有点绕,但是您始终可以将 MATLAB 代码与其他语言(例如 Java、.NET、C 等)进行接口,并在那里使用您习惯的功能。使用 Java,您可以确信您的解决方案是平台无关的,而 .NET 只能在 Windows 上运行(至少与 MATLAB 结合使用)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接