C++ 互斥体和 RTOS xMutex 之间的区别

Fal*_*lko 5 c++ multithreading mutex locking esp32

我正在尝试锁定 ESP32。显然,有不同的方法来实现锁:

  1. 有默认的 C++ 互斥体库:

    #include <mutex>
    
    std::mutex mtx;
    
    mtx.lock();
    
    mtx.unlock();
    
    Run Code Online (Sandbox Code Playgroud)
  2. RTOS 的实现如下:

    SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
    
    xSemaphoreTake(xMutex, portMAX_DELAY);
    
    xSemaphoreGive(xMutex);
    
    Run Code Online (Sandbox Code Playgroud)

我应该注意哪些根本区别吗?或者说它们是等价的?

rus*_*tyx 4

假设您使用ESP-IDF SDK,该工具链基于针对 xtensa-lx106 指令集的 GCC 5.2,并具有部分开源的 C 运行时库。

std::mutex在 GNU libstdc++ 中委托 pthread_mutex_lock/unlock 调用。ESP-IDF SDK 包含一个pthread 模拟层,我们可以在其中查看实际执行的pthread_mutex_lock操作pthread_mutex_unlock

static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickType_t tmo)
{
    if (!mux) {
        return EINVAL;
    }

    if ((mux->type == PTHREAD_MUTEX_ERRORCHECK) &&
        (xSemaphoreGetMutexHolder(mux->sem) == xTaskGetCurrentTaskHandle())) {
        return EDEADLK;
    }

    if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
        if (xSemaphoreTakeRecursive(mux->sem, tmo) != pdTRUE) {
            return EBUSY;
        }
    } else {
        if (xSemaphoreTake(mux->sem, tmo) != pdTRUE) {
            return EBUSY;
        }
    }

    return 0;
}

int IRAM_ATTR pthread_mutex_unlock(pthread_mutex_t *mutex)
{
    esp_pthread_mutex_t *mux;

    if (!mutex) {
        return EINVAL;
    }
    mux = (esp_pthread_mutex_t *)*mutex;
    if (!mux) {
        return EINVAL;
    }

    if (((mux->type == PTHREAD_MUTEX_RECURSIVE) ||
        (mux->type == PTHREAD_MUTEX_ERRORCHECK)) &&
        (xSemaphoreGetMutexHolder(mux->sem) != xTaskGetCurrentTaskHandle())) {
        return EPERM;
    }

    int ret;
    if (mux->type == PTHREAD_MUTEX_RECURSIVE) {
        ret = xSemaphoreGiveRecursive(mux->sem);
    } else {
        ret = xSemaphoreGive(mux->sem);
    }
    if (ret != pdTRUE) {
        assert(false && "Failed to unlock mutex!");
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它主要将调用委托给 RTOS 信号量 API,并进行一些额外的检查。

您很可能不需要/不想要这些支票。考虑到 esp32 芯片的微小 i-cache 和极其缓慢的串行 RAM,我宁愿尽可能靠近硬件(即,除非它完全满足std::mutex您的需要,否则不要使用)。