【问题标题】:msemaphore on linux?linux上的msemaphore?
【发布时间】:2010-10-24 15:05:25
【问题描述】:

AIX(如果有人关心的话,还有 HPUX)有一个很好的小功能,称为 msemaphores,它可以轻松同步多个进程共享的内存映射文件的粒度片段(例如记录)。有人知道 linux 中有类似的东西吗?

为明确起见,msemaphore 函数通过相关链接here 进行描述。

【问题讨论】:

    标签: linux multithreading ipc pthreads aix


    【解决方案1】:

    POSIX semaphores 可以放在进程之间共享的内存中,如果sem_init(3) 的第二个参数“pshared”为真。这似乎与msem 所做的相同。

    #include <semaphore.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    #include <time.h>
    #include <unistd.h>
    int main() {
        void *shared;
        sem_t *sem;
        int counter, *data;
        pid_t pid;
        srand(time(NULL));
        shared = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
                MAP_ANONYMOUS | MAP_SHARED, -1, 0);
        sem_init(sem = shared, 1, 1);
        data = shared + sizeof(sem_t);
        counter = *data = 0;
        pid = fork();
        while (1) {
            sem_wait(sem);
            if (pid)
                printf("ping>%d %d\n", data[0] = rand(), data[1] = rand());
            else if (counter != data[0]) {
                printf("pong<%d", counter = data[0]);
                sleep(2);
                printf(" %d\n", data[1]);
            }
            sem_post(sem);
            if (pid) sleep(1);
        }
    }
    

    这是一个非常愚蠢的测试,但它确实有效:

    $ cc -o test -lrt test.c
    $ ./test
    ping>2098529942 315244699
    pong<2098529942 315244699
    pong<1195826161 424832009
    ping>1195826161 424832009
    pong<1858302907 1740879454
    ping>1858302907 1740879454
    ping>568318608 566229809
    pong<568318608 566229809
    ping>1469118213 999421338
    pong<1469118213 999421338
    ping>1247594672 1837310825
    pong<1247594672 1837310825
    ping>478016018 1861977274
    pong<478016018 1861977274
    ping>1022490459 935101133
    pong<1022490459 935101133
    ...
    

    因为信号量在两个进程之间共享,所以pongs 不会从pings 获得交错的数据,尽管sleeps。

    【讨论】:

      【解决方案2】:

      这可以使用 POSIX 共享内存互斥锁来完成:

      pthread_mutexattr_t attr;
      int pshared = PTHREAD_PROCESS_SHARED;
      pthread_mutexattr_init(&attr);
      pthread_mutexattr_setpshared(&attr, &pshared);
      
      pthread_mutex_init(&some_shared_mmap_structure.mutex, &attr);
      pthread_mutexattr_destroy(&attr);
      

      现在您可以使用普通的 pthread_mutex_lock() 等调用从映射了它的多个进程中解锁和锁定 &some_shared_mmap_structure.mutex。

      实际上,您甚至可以按照以下方式实现 msem API:(未经测试)

      struct msemaphore {
          pthread_mutex_t mut;
      };
      
      #define MSEM_LOCKED 1
      #define MSEM_UNLOCKED 0
      #define MSEM_IF_NOWAIT 1
      
      msemaphore *msem_init(msemaphore *msem_p, int initialvalue) {
          pthread_mutex_attr_t attr;
          int pshared = PTHREAD_PROCESS_SHARED;
      
          assert((unsigned long)msem_p & 7 == 0); // check alignment
      
          pthread_mutexattr_init(&attr);
          pthread_mutexattr_setpshared(&attr, &pshared); // might fail, you should probably check
          pthread_mutex_init(&msem_p->mut, &attr); // never fails
          pthread_mutexattr_destroy(&attr);
      
          if (initialvalue)
              pthread_mutex_lock(&attr);
      
          return msem_p;
      }
      
      int msem_remove(msemaphore *msem) {
          return pthread_mutex_destroy(&msem->mut) ? -1 : 0;
      }
      
      int msem_lock(msemaphore *msem, int cond) {
          int ret;
          if (cond == MSEM_IF_NOWAIT)
              ret = pthread_mutex_trylock(&msem->mut);
          else
              ret = pthread_mutex_lock(&msem->mut);
      
          return ret ? -1 : 0;
      }
      
      int msem_unlock(msemaphore *msem, int cond) {
          // pthreads does not allow us to directly ascertain whether there are
          // waiters. However, a unlock/trylock with no contention is -very- fast
          // using linux's pthreads implementation, so just do that instead if
          // you care.
          //
          // nb, only fails if the mutex is not initialized
          return pthread_mutex_unlock(&msem->mut) ? -1 : 0;
      }
      

      【讨论】:

      • 虽然 OP 不太可能需要信号量(互斥量几乎可以满足所有目的),但您实现的不是信号量。提示:初始值可以取任何非负值,零表示锁定
      • 但是,OP 链接到的是一个互斥锁,它只称自己为信号量 - 至少,从我对相关文档的阅读来看:)
      • 仔细阅读后,您似乎是正确的。多么误导的名字!
      • 我的想法是它是作为信号量实现的,尽管我们认为它并像互斥体一样使用它。我认为这有两个原因。 (1) 没有限制,只有被锁定的进程/线程才能解锁它,从而打破了互斥锁的基本原则。 (2) 只有当 MSEM_IF_WAITERS 使用类似 sem_getvalue() [posix] 或者更可能是带有 GETNCNT/GETZCNT 选项 [sysv] 的 semop() 来跟踪这一点时,MSEM_IF_WAITERS 才有意义。我想在 IBM 或 HP 开放源代码之前我们无法确定。
      • 由于互斥锁的默认linux pthreads实现不做任何检查以确保锁的所有者是解锁它的人,那部分应该无关紧要:)无论如何,我不查看文档中的任何内容以讨论其他数量的服务员,但您可以轻松地扩展它以使用更多服务员制作信号量 - 毕竟也有一个可共享的条件变量选项
      【解决方案3】:

      在Linux下,你或许可以用SysV共享内存实现你想要的;快速谷歌搜索出现了this (rather old) guide,这可能会有所帮助。

      【讨论】:

      • 谢谢。 Msemaphores 提供了一些便利和简单,我希望它们已经实现,而不必自己构建。
      猜你喜欢
      • 2019-06-18
      • 2016-09-29
      • 2010-10-28
      • 2013-03-17
      • 2014-07-25
      • 2011-09-27
      • 2017-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多