【问题标题】:How do I synchronize two processes?如何同步两个进程?
【发布时间】:2008-10-30 00:29:46
【问题描述】:

我想在同一个工作站上的两个应用程序(进程)中使用一个硬件接口。硬件需要一个初始化调用,然后任何一个应用程序都使用相同的函数(在同一个库中)与硬件进行许多事务。

所以每个应用都应该是这样的:

main()
    // I don't know if another app already init'ed the HW
    ret = hw_init_lock(non-blocking)

    if ret = OK
        // no one else has done this, I have to
        init_hw()
    else
       //someone else has already init'ed the HW, I gotta make sure it stays that way
       //as long as I'm alive
       increment_hw_init_ref_counter()

    hw_trans_lock(blocking)
    hw_trans()
    hw_trans_unlock()
    ....

    //exit app, uninit hw if we are last out
    ret = decrement_hw_init_ref_counter()
    if ret == 0
        uninit_hw()

    exit(0)

我可以在两个应用程序之间共享的锁和引用计数调用中使用什么机制?我在想命名管道,即 mkfifo()。

【问题讨论】:

    标签: synchronization hardware process pthreads named-pipes


    【解决方案1】:

    POSIX semaphore 是要走的路。由于您希望跨进程共享相同的信号量,因此您需要使用命名信号量。:

    命名信号量由 /somename 形式的名称。二 进程可以在同一个上运行 通过传递相同的命名信号量 sem_open(3) 的名称。

    【讨论】:

      【解决方案2】:

      信号量和互斥量/条件变量是很好的、非常高性能的原语,适合在线程之间或进程之间使用。

      所有这些都基于在共享内存上执行的测试和设置或其他原子操作的想法(通常是基于现实)。

      如果您希望通过网络分发您的进程,那么信号量和互斥锁可能不适合您——它们只能在单台机器上工作。管道和套接字通常是网络可扩展的。

      互斥量、条件变量和信号量的简要总结:

      互斥体

      互斥锁是一种可以被锁定或解锁的原语。锁定它的进程/线程必须是解锁它的进程/线程。 所有权方面允许操作系统应用一些有趣的优化,例如优先级继承和优先级上限协议(以避免优先级倒置)。 然而,互斥体没有与之关联的计数。一般来说,你不能锁定一个已经锁定的互斥体,并保留它被“锁定两次”的内存(我认为有一些扩展允许这样做,但它们并非无处不在)

      条件变量

      互斥锁非常适合......嗯,互斥。但是,如果您需要阻止与您有互斥的对象相关联的条件怎么办?为此,您使用条件变量或 CV。 CV 与互斥锁相关联。例如,假设我有一个我的进程想要访问的输入数据队列。一个人抓住互斥锁,这样它就可以查看队列而不必担心干扰。但是,它发现队列为空,并希望等待队列中的某些内容。因此,它等待“队列非空”条件变量。这里有趣的部分是,因为 CV 与互斥锁相关联,一旦条件变量发出信号,互斥锁就会自动重新获取。因此,一旦进程在等待 CV 后醒来,它就知道它再次拥有对队列的独占访问权限。它知道的是队列上是否真的有任何东西——也许有两个进程在等待 CV——一个东西进来了——第一优先级进入并让“东西”出队在第二件事醒来之前。因此,无论何时使用 CV,都需要重新检查条件,如下所示:

      mutex_enter(m);
      while (! condition) {
         cond_wait(m, c); // drop mutex lock;  wait on cv;  reacquire mutex
      }
      //processing related to condition
      mutex_exit(m);
      

      信号量

      好的,那就是互斥体和条件变量。信号量更简单。它们可以通过任何进程递增和递减。它们有记忆——它们会计数——因此您可以使用它们来确定发生了多少情况。条件变量并非如此。此外,由于信号量可以由一个进程递减并由另一个进程递增,因此它们不具有所有权方面——因此没有优先级继承,也无法避免优先级反转。

      现在,最后——所有这些机制都需要共享内存才能有效实现。这对您来说可能很好,但请注意——如果您认为您的应用程序最终可能会被分发,那么互斥锁、条件变量和信号量可能不适合您。管道和套接字虽然开销要高得多,但有可能相当直接地在网络上扩展。

      【讨论】:

        【解决方案3】:

        使用POSIX semaphores

        【讨论】:

          【解决方案4】:

          由于您只需要一个信号量计数,因此互斥体就足够了。

          【讨论】:

          • POSIX 信号量可以在不相关的进程之间共享,而 pthread 互斥锁则不能。
          【解决方案5】:

          我认为如果我们想要同步多个正在运行的进程,那么我们可以使用一种非常简单的技术,称为文件锁。

          更多详情请参考这篇文章: http://blog.markedup.com/2014/07/easy-mode-synchronizing-multiple-processes-with-file-locks/

          【讨论】:

          • 链接中的文章不再可用。
          【解决方案6】:

          我认为

          ...在两个应用程序之间共享?

          意味着您希望这两个东西作为单独的进程运行?如果这不是真的,并且它们作为单个进程运行(具有多个线程),那么信号量和互斥体的建议是最好的选择并且应该非常简单。

          请注意,答案将取决于您访问此硬件的具体方式。例如,如果它通过文件公开,则可以使用正常的文件锁定。

          但是,如果您尝试跨两个进程同步对硬件的访问,那就另当别论了。 我想首先要说的是,如果可以的话,同步会更容易,让一个进程负责访问硬件。在此模型中,您可能有一个进程充当硬件的服务器 - 接受来自其他进程的请求并代表它们执行读取和写入。 几乎任何形式的进程间通信都是合适的,但为简单起见,消息队列 (link) 之类的东西可能适合一些适当的数据结构(例如,指示它是读操作还是写操作的标志,从基础偏移您的硬件地址、字节数、缓冲区(在写入的情况下))

          如果将所有直接硬件访问放到一个进程中是不合适的,那么您必须使用适当的同步方案。 我会调查文件锁的使用(并实现一个基本的互斥方案),或者使用命名信号量(正如 albertb 所建议的)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-08
            • 1970-01-01
            相关资源
            最近更新 更多