Общее состояние гонки

Я новичок в C и хотел знать об условиях гонки. Я нашел это в Интернете, и он попросил найти условие гонки и решение для этого.

Мой анализ состоит в том, что условие гонки в методе create-thread() имеет условие гонки, особенно в if-else заявление. Таким образом, при доступе к методу другой поток может быть создан или удален во время check-and-act и thread_amt будет отключен.

Чтобы не было состояния гонки, затем заблокируйте if-else используя мьютекс, семафоры и т. д.?

Может ли кто-нибудь исправить меня, если я ошибаюсь, и может показать мне, как реализовать мьютекс?

#define MAXT 255
int threads_amt = 0;
int create-thread() // create a new thread
{
    int tid;
    if (threads_amt == MAXT) return -1;
    else
    {
        threads_amt++;
        return tid;
    }
}
void release-thread()
{
    /* release thread resources */
    --threads_amt;
}

2 ответа

Да, условие гонки в этом случае происходит, потому что у вас нет никаких гарантий, что проверка и манипулирование threads_amt произойдет без прерывания / выполнения другого потока.

Три решения от макушки головы:

1) Принудительное взаимное исключение этой части кода с использованием двоичного семафора (или мьютекса) для защиты части if-else.

2) Используйте семафор с начальным значением MAXT, а затем, после вызова create_thread (помните, вы не можете использовать дефисы в именах функций!), Используйте "wait()" (в зависимости от типа семафора, он может иметь разные имена (например, sem_wait())). После этого создайте тему. При вызове release_thread() просто используйте "signal()" (sem_post(), когда используете semaphore.h).

3) Это скорее "аппаратное" решение: вы можете предположить, что вам предоставляется элементарная функция, которая выполняет всю часть if-else и, следовательно, позволяет избежать любой проблемы состояния гонки.

Из этих решений наиболее простым (на основе уже имеющегося кода) является первое.

Давайте использовать semaphore.hСемафоры:

#define MAXT 255

// Global semaphore 
sem_t s;
int threads_amt = 0;

int main () {
    ...
    sem_init (&s, 0, 1); // init semaphore (initial value = 1)
    ...
}


int create_thread() // create a new thread
{
    int tid;
    sem_wait(&s);
    if (threads_amt == MAXT) {
        sem_post(&s); // the semaphore is now available
        return -1;
    }
    else
    {
        threads_amt++;
        sem_post(&s); // the semaphore is now available
        return tid;
    }
}
void release_thread()
{
    /* release thread resources */
    sem_wait(&s);
    --threads_amt;
    sem_post(&s);
}

Это должно работать просто отлично.

Надеюсь это понятно. Если это не так, я предлагаю вам изучить, как работают семафоры (использовать Интернет или купить книгу по операционной системе). Кроме того, вы упомянули, что вы новичок в C: ИМХО, вам следует начать с чего-то более простого, чем это: семафоры - это не совсем то, что вы хотите узнать после "привет мира";-)

Состояние гонки не в if() заявления.

Именно с доступом к переменной threads_amt это потенциально может быть изменено и доступно одновременно в нескольких потоках.

По сути, любой поток, который изменяет переменную, должен иметь монопольный доступ, чтобы избежать состояния гонки. Это означает, что весь код, который изменяет переменную или считывает ее значение, должен быть синхронизирован (например, сначала захватить мьютекс, а затем освободить). Читателям не обязательно нужен монопольный доступ (например, чтение двух потоков одновременно не обязательно будет влиять друг на друга), но авторам это нужно (поэтому избегайте чтения значения при попытке изменить его в другом потоке) - такие соображения могут быть возможностью используйте методы синхронизации, отличные от мьютекса, например семафоры.

Чтобы использовать мьютекс, необходимо сначала его создать (например, во время запуска проекта). Затем возьмите его, когда это необходимо, и не забудьте отпустить его, когда закончите. Каждая функция должна минимизировать время, в течение которого она удерживает мьютекс, поскольку другие потоки, пытающиеся захватить мьютекс, будут вынуждены ждать.

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

Реальный код для реализации зависит от того, какую библиотеку потоков вы используете (поэтому вам нужно прочитать документацию), но концепции совпадают. Все библиотеки потоков имеют функции для создания, захвата (или ввода) и освобождения мьютексов, семафоров и т. Д. И т. Д.

Другие вопросы по тегам