Как избежать голодания при попытке использовать реализацию «многие ко многим» - PullRequest
0 голосов
/ 27 ноября 2018

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

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

Проблема: наблюдается заметное голодание, когда существует более 1 потока каждого типа (в моем случае потоки с идентификатором 0 никогда не использовали его).Я попытался исправить это, добавив дополнительный семафор, чтобы служить в качестве очереди.

Наблюдение: это очень похоже на проблему читателей-писателей, за исключением того, что существует множество критериев доступа.(он может использоваться несколькими потоками одного типа). В последнее время я довольно часто ломаю голову над этой проблемой, и я не могу понять, как мне к этому подойти.

Теперь для некоторого кода:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <pthread.h>
#include <semaphore.h>

#define MAX_RAND 100
#define TRUE 1
#define FALSE 0

#define WHITES 3
#define BLACKS 2

#define MAX_WORLOAD 10

sem_t semaphore;
sem_t resource_semaphore;
sem_t service_queue;
volatile int resource = 0;
volatile int currentWhites = 0;
volatile int currentBlacks = 0;

typedef struct
{
    char *type;
    int *id;
} data;

void *white(void *args)
{
    data *thread_data = (data *)args;
    int id = *(thread_data->id);
    char *type = thread_data->type;

    for (int i = 0; i < MAX_WORLOAD; i++)
    {
        sem_wait(&service_queue);
        sem_wait(&semaphore);
        sem_post(&service_queue);

        currentWhites++;
        if (currentWhites == 1)
        {
            sem_wait(&resource_semaphore);
        }
        sem_post(&semaphore);

        sem_wait(&semaphore);

        currentBlacks--;
        resource = rand() % MAX_RAND;
        printf("Thread %d of type %s has updated resource to %d\n\n", id, type, resource);

        if (currentWhites == 0)
        {
            sem_post(&resource_semaphore);
        }

        sem_post(&semaphore);
    }
}

void *black(void *args)
{
    data *thread_data = (data *)args;
    int id = *(thread_data->id);
    char *type = thread_data->type;

    for (int i = 0; i < MAX_WORLOAD; i++)
    {
        sem_wait(&service_queue);
        sem_wait(&semaphore);
        sem_post(&service_queue);
        currentBlacks++;
        if (currentBlacks == 1)
        {
            sem_wait(&resource_semaphore);
        }
        sem_post(&semaphore);

        sem_wait(&semaphore);

        currentBlacks--;
        resource = rand() % MAX_RAND;
        printf("Thread %d of type %s has updated resource to %d\n\n", id, type, resource);

        if (currentBlacks == 0)
        {
            sem_post(&resource_semaphore);
        }

        sem_post(&semaphore);
    }
}

data *initialize(pthread_t threads[], int size, char *type)
{
    data *args = malloc(sizeof(data) * size);
    int *id = malloc(sizeof(int));
    void *function;

    if (type == "WHITE")
    {
        function = white;
    }
    else
    {
        function = black;
    }

    for (int i = 0; i < size; i++)
    {
        *id = i;
        args[i].type = type;
        args[i].id = id;
        printf("Initializing %d of type %s\n", *args[i].id, args[i].type);
        pthread_create(&threads[i], NULL, function, (void **)&args[i]);
    }

    return args;
}

void join(pthread_t threads[], int size)
{
    for (int i = 0; i < size; i++)
    {
        pthread_join(threads[i], NULL);
    }
}

void initialize_locks()
{
    sem_init(&semaphore, 0, 1);
    sem_init(&resource_semaphore, 0, 1);
    sem_init(&service_queue, 0, 1);
}

int main()
{
    initialize_locks();
    pthread_t whites[WHITES];
    pthread_t blacks[BLACKS];
    char *white = "white";
    char *black = "black";
    data *whites_arg = initialize(whites, WHITES, white);
    data *blacks_arg = initialize(blacks, BLACKS, black);

    join(whites, WHITES);
    join(blacks, BLACKS);

    free(whites_arg);
    free(blacks_arg);
    return 0;
}

1 Ответ

0 голосов
/ 27 ноября 2018

Если вы хотите принудительно чередовать два типа потоков, обращающихся к одной вещи, вы можете использовать два семафора.Сделайте так, чтобы у черных и белых были свои собственные семафоры, начните один семафор с 0 клавиш, а другой - с 10 или чем-то еще, затем сделайте так, чтобы у белых был ключ к черному семафору, а у черных - ключ кбелый семафор, таким образом, если у вас есть 10 белых нитей, когда одна из них разблокируется, вы не сможете вставить 10-ю белую нить, но вы сможете вставить черную нить, чтобы, когда всебелые нити выпускают свои ключи, у вас не будет белых нитей, которые сейчас обращаются к этой вещи.

TL; DR: два семафора, которые публикуют друг друга вместо себя, позволят чередовать группы, однако независимо от этой операции необходимо также убедиться, что белые не уходят, пока черные еще находятся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...