Семафор — это конструкция синхронизации, используемая в операционных системах для управления доступом к общим ресурсам между несколькими процессами или потоками. По сути, это переменная или абстрактный тип данных, который обеспечивает две основные операции: «ожидание» и «сигнал» (также известные как операции «P» и «V» соответственно).

Вот как работают семафоры:

Операция ожидания (P): Когда процесс/поток хочет получить доступ к общему ресурсу, он сначала выполняет операцию «ожидания» на семафоре, связанном с этим ресурсом. Если значение семафора положительное (больше 0), оно уменьшается на 1 и доступ к ресурсу продолжается. Если значение семафора равно нулю, что указывает на то, что ресурс в настоящее время используется другим процессом/потоком, процесс/поток блокируется или приостанавливается до тех пор, пока семафор не станет доступным.

Сигнальная операция (V): когда процесс/поток завершает использование общего ресурса, он выполняет «сигнальную» операцию на семафоре, которая увеличивает значение семафора на 1. Эта операция указывает, что ресурс теперь доступен для других процессов/потоков. ожидание этого. Если есть какие-либо заблокированные процессы/потоки, ожидающие семафора, один из них пробуждается и ему предоставляется доступ к ресурсу.

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

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

#include <stdio.h>
#include <pthread.h>

typedef struct {
    pthread_mutex_t mutex;
    pthread_cond_t condition;
    int value;
} semaphore;

void semaphore_init(semaphore* sem, int initial_value) {
    pthread_mutex_init(&(sem->mutex), NULL);
    pthread_cond_init(&(sem->condition), NULL);
    sem->value = initial_value;
}

void semaphore_wait(semaphore* sem) {
    pthread_mutex_lock(&(sem->mutex));
    while (sem->value <= 0) {
        pthread_cond_wait(&(sem->condition), &(sem->mutex));
    }
    sem->value--;
    pthread_mutex_unlock(&(sem->mutex));
}

void semaphore_signal(semaphore* sem) {
    pthread_mutex_lock(&(sem->mutex));
    sem->value++;
    pthread_cond_signal(&(sem->condition));
    pthread_mutex_unlock(&(sem->mutex));
}

void* thread_function(void* arg) {
    semaphore* sem = (semaphore*)arg;
    
    printf("Thread waiting\n");
    semaphore_wait(sem);
    
    printf("Thread acquired the semaphore\n");
    // Perform some critical section or shared resource access here
    
    printf("Thread releasing the semaphore\n");
    semaphore_signal(sem);
    
    return NULL;
}

int main() {
    semaphore sem;
    semaphore_init(&sem, 1); // Initialize the semaphore with initial value 1
    
    pthread_t thread;
    pthread_create(&thread, NULL, thread_function, (void*)&sem);
    
    // Main thread also performs some work
    printf("Main thread performing some work\n");
    
    // Main thread waits for the semaphore
    printf("Main thread waiting\n");
    semaphore_wait(&sem);
    
    printf("Main thread acquired the semaphore\n");
    // Perform some critical section or shared resource access here
    
    printf("Main thread releasing the semaphore\n");
    semaphore_signal(&sem);
    
    pthread_join(thread, NULL);
    
    return 0;
}

Надеюсь, вам понравилось это.

https://www.youtube.com/@endeavourmonk