[ESP32] Phân biệt Mutex và Semaphore trong xử lý đa nhân trên ESP32

Arduino 25 Th07 2024

Mutex và Semaphore là hai cơ chế đồng bộ hóa quan trọng được sử dụng trong lập trình đa luồng và hệ điều hành. Chúng giúp quản lý truy cập vào tài nguyên chia sẻ và đồng bộ hóa giữa các tiến trình hoặc luồng.

Trong bài viết này, sẽ có một số ví dụ minh họa:

  • Trong ví dụ Mutex, chúng ta đảm bảo rằng chỉ một task có thể in ra màn hình tại một thời điểm.
  • Trong ví dụ Binary Semaphore, chúng ta sử dụng nó để báo hiệu giữa producer và consumer task.
  • Trong ví dụ Counting Semaphore, chúng ta mô phỏng việc quản lý một nhóm tài nguyên giới hạn, cho phép tối đa 3 task sử dụng tài nguyên cùng một lúc.

Những ví dụ này minh họa cách Mutex và Semaphore được sử dụng trong các tình huống khác nhau để quản lý tài nguyên và đồng bộ hóa giữa các task trong môi trường đa nhiệm.

1. Mutex (Mutual Exclusion):

1.1. Chức năng:

  • Đảm bảo quyền truy cập độc quyền vào một tài nguyên chia sẻ.
  • Chỉ có một task có thể sở hữu Mutex tại một thời điểm.

1.2. Trường hợp sử dụng:

  • Bảo vệ dữ liệu hoặc tài nguyên được chia sẻ giữa nhiều task.
  • Đảm bảo tính nhất quán khi truy cập vào các cấu trúc dữ liệu phức tạp.

1.3. Ví dụ cơ bản:

SemaphoreHandle_t printMutex;

void printTask(void *pvParameters) {
    char *taskName = (char*)pvParameters;
    while(1) {
        if(xSemaphoreTake(printMutex, portMAX_DELAY) == pdTRUE) {
            Serial.print("Task ");
            Serial.print(taskName);
            Serial.println(" is printing");
            xSemaphoreGive(printMutex);
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void setup() {
    Serial.begin(115200);
    printMutex = xSemaphoreCreateMutex();
    xTaskCreate(printTask, "Task1", 2048, (void*)"1", 1, NULL);
    xTaskCreate(printTask, "Task2", 2048, (void*)"2", 1, NULL);
}

2. Semaphore:

2.1. Chức năng:

  • Kiểm soát truy cập vào một tập hợp các tài nguyên giới hạn.
  • Có thể cho phép nhiều task truy cập đồng thời (tùy thuộc vào số lượng tài nguyên).

2.2. Trường hợp sử dụng:

  • Đồng bộ hóa giữa các task.
  • Quản lý một nhóm tài nguyên giới hạn (ví dụ: pool of connections).
  • Signaling giữa các task.

2.3. Ví dụ cơ bản (Binary Semaphore for signaling):

SemaphoreHandle_t dataSemaphore;

void dataProducerTask(void *pvParameters) {
    while(1) {
        // Giả lập tạo dữ liệu
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        Serial.println("Data produced");
        xSemaphoreGive(dataSemaphore);
    }
}

void dataConsumerTask(void *pvParameters) {
    while(1) {
        if(xSemaphoreTake(dataSemaphore, portMAX_DELAY) == pdTRUE) {
            Serial.println("Data consumed");
        }
    }
}

void setup() {
    Serial.begin(115200);
    dataSemaphore = xSemaphoreCreateBinary();
    xTaskCreate(dataProducerTask, "Producer", 2048, NULL, 1, NULL);
    xTaskCreate(dataConsumerTask, "Consumer", 2048, NULL, 1, NULL);
}

2.4. Ví dụ về Counting Semaphore:

SemaphoreHandle_t resourceSemaphore;
const int MAX_RESOURCES = 3;

void resourceUser(void *pvParameters) {
    char *taskName = (char*)pvParameters;
    while(1) {
        if(xSemaphoreTake(resourceSemaphore, portMAX_DELAY) == pdTRUE) {
            Serial.print("Task ");
            Serial.print(taskName);
            Serial.println(" acquired a resource");
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            xSemaphoreGive(resourceSemaphore);
            Serial.print("Task ");
            Serial.print(taskName);
            Serial.println(" released a resource");
        }
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

void setup() {
    Serial.begin(115200);
    resourceSemaphore = xSemaphoreCreateCounting(MAX_RESOURCES, MAX_RESOURCES);
    xTaskCreate(resourceUser, "Task1", 2048, (void*)"1", 1, NULL);
    xTaskCreate(resourceUser, "Task2", 2048, (void*)"2", 1, NULL);
    xTaskCreate(resourceUser, "Task3", 2048, (void*)"3", 1, NULL);
    xTaskCreate(resourceUser, "Task4", 2048, (void*)"4", 1, NULL);
}

Tags

Tony Phạm

Là một người thích vọc vạch và tò mò với tất cả các lĩnh vực từ khoa học tự nhiên, lập trình, thiết kế đến ... triết học. Luôn mong muốn chia sẻ những điều thú vị mà bản thân khám phá được.