Использование семафоров для создания поточно-безопасного стека в C? - PullRequest
1 голос
/ 06 мая 2020

Я пытаюсь сделать стек, в котором я реализовал потокобезопасность с использованием семафоров. Это работает, когда я помещаю sh один объект в стек, но терминал зависает, как только я пытаюсь поместить sh второй элемент в стек или вытолкнуть элемент из стека. Это то, что у меня есть до сих пор, и я не уверен, где я напортачил. Все соответствует требованиям, но терминал просто зависает, как было сказано ранее.

Вот где я создаю стек

sem_t selements, sspace;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

BlockingStack *new_BlockingStack(int max_size)
{
    sem_init(&selements, 0, 0);
    sem_init(&sspace, 0, max_size);

    BlockingStack *newBlockingStack = malloc(sizeof(BlockingStack));
    newBlockingStack->maxSize = max_size;
    newBlockingStack->stackTop = -1;
    newBlockingStack->element = malloc(max_size * sizeof(void *));

    if (newBlockingStack == NULL)
    {
        return NULL;
    }

    if (newBlockingStack->element == NULL)
    {
        free(newBlockingStack);
        return NULL;
    }

    return newBlockingStack;
}

А вот Pu sh и Pop:

bool BlockingStack_push(BlockingStack *this, void *element)
{
    sem_wait(&sspace);
    pthread_mutex_lock(&m);


    if (this->stackTop == this->maxSize - 1)
    {
        return false;
    }
    if (element == NULL)
    {
        return false;
    }
    this->element[++this->stackTop] = element;
    return true;

    pthread_mutex_unlock(&m);
    sem_post(&selements);

}

void *BlockingStack_pop(BlockingStack *this)
{
    sem_wait(&selements);
    pthread_mutex_lock(&m);

    if (this->stackTop == -1)
    {
        return NULL;
    }
    else
    {
        return this->element[this->stackTop--];
    }

    pthread_mutex_unlock(&m);
    sem_post(&sspace);
}

Ответы [ 3 ]

1 голос
/ 06 мая 2020

Для обеспечения безопасности потоков у вас уже используется мьютекс (pthread_mutex_lock(&m) and pthread_mutex_unlock(&m)). Для этого достаточно использовать такое взаимное исключение. Как только один поток получает мьютекс, другой поток блокируется при вызове pthread_mutex_lock(&m). И только поток, в настоящее время получающий мьютекс, может вызывать pthread_mutex_unlock(&m).

1 голос
/ 06 мая 2020

ПРЕДЛАГАЕМЫЕ ИЗМЕНЕНИЯ:

sem_t sem;
...
BlockingStack *new_BlockingStack(int max_size)
{
    sem_init(&sem, 0, 1);
    ...

bool BlockingStack_push(BlockingStack *this, void *element)
{
    sem_wait(&sem);
    ...
    sem_post(&sem);
    ...

В частности:

  • Я бы инициализировал только один семафорный объект, если только я не был УВЕРЕН Мне нужны были другие

  • Я бы использовал тот же семафор для pu sh () и pop ()

  • pshared: 0 должен будет достаточно для синхронизации различных потоков pthread внутри вашего единого процесса.

  • Инициализируйте семафор как 1, потому что первое, что вы сделаете для «pu sh» или «pop "равно sem_wait().

0 голосов
/ 06 мая 2020

Хорошо, я работал над этим и наконец нашел ответ после небольшого rnet исследования и отладки моего кода. Ошибка заключалась в mutex_unlock, и sem_post должен был появиться перед возвратом.

Возьмем, к примеру, мой pop:

void *BlockingStack_pop(BlockingStack *this)
{
    sem_wait(&selements);
    pthread_mutex_lock(&m);

    if (this->stackTop == -1)
    {
        return NULL;
    }
    else
    {
        return this->element[this->stackTop--];
    }

    pthread_mutex_unlock(&m);
    sem_post(&sspace);
}

обратите внимание, как pthread_mutex_unlock (& ​​m); и sem_post (& sspace); идут после возврата, на самом деле они должны быть помещены перед каждым возвратом следующим образом:

void *BlockingStack_pop(BlockingStack *this)
{
...
    pthread_mutex_unlock(&m);
    sem_post(&sspace);
        return NULL;
...
        pthread_mutex_unlock(&m);
    sem_post(&sspace);
        return this->element[this->stackTop--];
...

}
...