мьютекс разделяемой памяти с указателями структуры - PullRequest
0 голосов
/ 17 октября 2018

Я ищу отзывы о том, правильно ли я делаю следующее.Я работаю над портированием некоторых окон в режиме реального времени, которые активно использовали именованные мьютексы.Это заняло некоторый поиск, но я наткнулся на некоторые вещи, говорящие о том, что вы можете использовать разделяемую память в качестве взаимных исключений в Linux, используя shm open.

Я не могу включить весь код здесь, но я собрал ключевые области, которые мне нужнынекоторые возвращаются.Мои вопросы: правильно ли я настраиваю область общей памяти и мьютекс, а также правильно ли установлены мои указатели, а также как использовать их для блокировки / разблокировки.

volatile struct GenQ {
    volatile pthread_mutex_t *qMutexId
    volatile sem_t  qSemId
    volatile int    nexton
    volatile int    nextoff
}

typedef struct Node{
    void                *qid
    char                shmname[80]
    sem_t               *semid
    pthread_mutex_t     *mutexID
    struct node         *next
    struct node         *prev   
}


void * init (const char *qname)
{
    struct GenQ *myq;
    char mtxstr[80];
    pthread_mutex_t *mutexQueAccess;
    int mode = S_IRWXU | S_IRWXG;
    int fd = 0;
    int status = 0;

    mtxstr[0] = "\0";
    strcpy(mtxstr,"/");
    strcat(mtxstr, qname);
    strcat(mtxstr, "_MTX");

    fd = shm_open(mtxstr, O_CREATE | O_RDWR | O_TRUNC, mode);
    if (fd == -1)
        //err handling stuff

    status = ftruncate(fd, sizeof(pthread_mutex_t));
    if(status==0){
        //err handling stuff

    mutexQueAccess = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t), 
    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(mutexQueAccess == MAP_FAILED)
    //err handling stuff

    pthread_mutexattr_t mutexAttr;
    pthread_mutexattr_init(&mutexAttr);
    pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(mutexQueAccess, &mutexAttr);

    myq->qMutexId = mutexQueAccess;

    newNode = (Node*)malloc(sizeof(node));
    newNode->mutedID = mutexQueAccess;
    //add node to link list

}

void * openQ(*const char *qname)
{
    pthread_mutex_t *mutexQueAccess;
    int fd = 0;
    int status = 0;
    char mtxstr[80];
    int mode = S_IRWXU | S_IRWXG;

    mtxstr[0] = "\0";
    strcpy(mtxstr,"/");
    strcat(mtxstr, qname);
    strcat(mtxstr, "_MTX");

    fd = shm_open(mtxstr, O_CREATE | O_RDWR, mode);
        //check fd for err

    mutexQueAccess = (pthread_mutex_t *)mmap(NULL, sizeof(pthread_mutex_t), 
    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        //check for err on mmap

    newNode = (Node*)malloc(sizeof(node));
    newNode->mutedID = mutexQueAccess;
    //add node to link list


}

void * enque(const char *qname, char *msg_data)
{
    node = //search for node
    pthread_mutex_lock(&(node->mutexQueAccess))

}

1 Ответ

0 голосов
/ 17 октября 2018

Я делаю то же самое в некотором коде, который у меня есть, и он выглядит очень похоже - частично.Идея действительно довольно проста.Размер пространства, выделенного для мьютекса, составляет ровно sizeof(pthread_mutex_t).Вы создаете общий файл, mmap его и инициализируете мьютекс в одном процессе, тогда другие могут просто mmap файл и установить на него указатель pthread_mutex_t *.

Одна вещь, которую я не понимаюэто struct GenQ часть.Ключевые слова volatile намекают на то, что эта структура уже находится в общей памяти.Однако, если в общей памяти , указатель мьютекса, который вы там храните , не будет действительным вне процесса, который его создал.Сам мьютекс может находиться в общей памяти, и другие процессы могут иметь указатель на мьютекс, но точное местоположение области общей памяти в их виртуальном адресном пространстве может отличаться, следовательно, их значение указателя также будет отличаться (и, следовательно, указатель должен быть закрытым для процесса).

Итак, если структура GenQ уже уже в общей памяти, почему бы просто не объявить pthread_mutex_t ( not указатель - пространство для фактического мьютекса) в структуре GenQ, а затем выполните ту же инициализацию из вашего основного процесса, что и в приведенном выше коде.Тогда вам не нужен отдельный файл общей памяти для мьютекса;он будет находиться в той же области разделяемой памяти, что и другая информация об очереди.

Также рассмотрите возможность добавления атрибута PTHREAD_MUTEX_ROBUSTpthread_mutexattr_setrobust) в мьютекс, чтобы вы могли восстановить его в случаегде происходит сбой одного из процессов при удержании блокировки.

Этот код выглядит примерно так:

    int err = pthread_mutex_lock(mutex_ptr);
    if (err) {
        if (err == EOWNERDEAD) {
            WARN("Mutex owner died while holding -- recovering");
            err = pthread_mutex_consistent(mutex_ptr);
            if (err)
                 FATAL("Huh?");
        } else {
            FATAL("Wha?");
        }
    }

Наконец, я бы сказал, что вы используете volatile.Это не является ни необходимым, ни достаточным.Если вы обращаетесь к разделяемым переменным, когда вы держите мьютекс, квалификатор volatile не нужен.Если вы не удерживаете мьютекс, то volatile сам по себе недостаточно для обеспечения правильной синхронизации - вам все равно нужно будет использовать какой-то атомный инкремент / декремент или атомарный метод сравнения и замены.

...