Msemaphore на Linux? - PullRequest
       22

Msemaphore на Linux?

2 голосов
/ 08 мая 2009

В AIX (и HPUX, если кому-то все равно) есть замечательная небольшая функция, называемая msemaphores, которая позволяет легко синхронизировать гранулированные фрагменты (например, записи) файлов с отображением в памяти, совместно используемых несколькими процессами. Кто-нибудь знает что-то сопоставимое в Linux?

Для ясности, функции msemaphore описываются следующими ссылками здесь .

Ответы [ 3 ]

1 голос
/ 08 мая 2009

Семафоры POSIX могут быть помещены в память, разделяемую между процессами, если второй аргумент sem_init(3), "pshared", равен true Это похоже на то, что делает 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
...

Поскольку семафор совместно используется двумя процессами, pong s не получает чередующиеся данные от ping s, несмотря на sleep s.

1 голос
/ 08 мая 2009

Это можно сделать с помощью мьютексов с общей памятью 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);

Теперь вы можете разблокировать и заблокировать & some_shared_mmap_structure.mutex, используя обычные вызовы pthread_mutex_lock () и т. Д., Из нескольких процессов, для которых это сопоставлено.

Действительно, вы даже можете реализовать API msem с точки зрения этого: (не проверено)

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;
}
0 голосов
/ 08 мая 2009

В Linux вы можете достичь желаемого с помощью общей памяти SysV; быстрое прибегание к помощи оказалось это (довольно старое) руководство , которое может помочь.

...