2009-05-07 8 views
2

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

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

ответ

0

В Linux вы можете добиться того, чего хотите с общей памятью SysV; быстрый googling оказался this (rather old) guide, что может помочь.

+0

Спасибо. Msemaphores предлагает некоторую удобство и простоту, которые, как я надеялся, уже были реализованы, а не самим создавать. – Duck

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 
... 

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

1

Это может быть сделано с использованием 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() и т.д. вызовы, из нескольких процессов, которые она отображается.

В самом деле, вы можете даже реализовать 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; 
} 
+0

Хотя маловероятно, что OP требует семафора (мьютекса достаточно для почти всех целей), то, что вы реализовали, - это * не * семафор. Подсказка: начальное значение может принимать любое неотрицательное значение, а ноль означает * заблокировано *. – ephemient

+0

Однако, что связанное с OP было мьютеком, который только называл себя семафором - по крайней мере, из моего чтения рассматриваемых документов :) – bdonlan

+0

При более близком повторном чтении кажется, что вы правы. Какое обманчивое имя! – ephemient