C++ mutex 和 RTOS xMutex 的区别
Difference between C++ mutex and RTOS xMutex
我正在尝试锁定 ESP32。显然,有不同的方法来实现锁:
有默认的C++互斥库:
#include <mutex>
std::mutex mtx;
mtx.lock();
mtx.unlock();
-
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
xSemaphoreTake(xMutex, portMAX_DELAY);
xSemaphoreGive(xMutex);
我应该注意哪些根本差异?
或者它们是等价的?
Are there fundamental differences I should be aware of?
我不熟悉你在第二个例子中调用的 API,但看起来你的 xMutex
变量引用了 counting semaphore。 "semaphore" 抽象比 "mutex" 抽象更强大。也就是说,您始终可以使用信号量代替互斥量,但是在某些算法中互斥量不能代替信号量。
我喜欢将信号量视为无信息标记的 blocking queue。 "give" 操作将一个令牌放入队列,而 "take" 从队列中取出一个令牌,如果队列恰好在 take( ) 被调用。
P.S., 为了使用信号量代替互斥锁,当互斥锁应为 "free" 时,您需要它包含一个标记,而当mutex 应该是 "in use." 这意味着,您需要创建信号量的代码确保它在开始时包含一个标记
您示例中的 xMutex = xSemaphoreCreateMutex()
语句没有明确显示新信号量包含多少标记。如果它是零个标记,那么您可能希望下一行代码 "give()" 一个标记以完成初始化。
假设您使用的是 ESP-IDF SDK,工具链基于 GCC 5.2,针对 xtensa-lx106 指令集,具有部分开源的 C 运行时库。
GNU libstdc++ 中的 std::mutex
委托给 pthread_mutex_lock/unlock 调用。 ESP-IDF SDK 包含一个 pthread emulation layer, where we can see what pthread_mutex_lock
and 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;
}
如您所见,它主要将调用委托给 RTOS 信号量 API,并进行一些额外的检查。
您很可能没有 need/want 这些支票。考虑到 esp32 芯片的微小 i-cache 和极慢的串行 RAM,我宁愿尽可能靠近硬件(即不要使用 std::mutex
除非它完全满足你的需要)。
我正在尝试锁定 ESP32。显然,有不同的方法来实现锁:
有默认的C++互斥库:
#include <mutex> std::mutex mtx; mtx.lock(); mtx.unlock();
-
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex(); xSemaphoreTake(xMutex, portMAX_DELAY); xSemaphoreGive(xMutex);
我应该注意哪些根本差异? 或者它们是等价的?
Are there fundamental differences I should be aware of?
我不熟悉你在第二个例子中调用的 API,但看起来你的 xMutex
变量引用了 counting semaphore。 "semaphore" 抽象比 "mutex" 抽象更强大。也就是说,您始终可以使用信号量代替互斥量,但是在某些算法中互斥量不能代替信号量。
我喜欢将信号量视为无信息标记的 blocking queue。 "give" 操作将一个令牌放入队列,而 "take" 从队列中取出一个令牌,如果队列恰好在 take( ) 被调用。
P.S., 为了使用信号量代替互斥锁,当互斥锁应为 "free" 时,您需要它包含一个标记,而当mutex 应该是 "in use." 这意味着,您需要创建信号量的代码确保它在开始时包含一个标记
您示例中的 xMutex = xSemaphoreCreateMutex()
语句没有明确显示新信号量包含多少标记。如果它是零个标记,那么您可能希望下一行代码 "give()" 一个标记以完成初始化。
假设您使用的是 ESP-IDF SDK,工具链基于 GCC 5.2,针对 xtensa-lx106 指令集,具有部分开源的 C 运行时库。
GNU libstdc++ 中的std::mutex
委托给 pthread_mutex_lock/unlock 调用。 ESP-IDF SDK 包含一个 pthread emulation layer, where we can see what pthread_mutex_lock
and 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;
}
如您所见,它主要将调用委托给 RTOS 信号量 API,并进行一些额外的检查。
您很可能没有 need/want 这些支票。考虑到 esp32 芯片的微小 i-cache 和极慢的串行 RAM,我宁愿尽可能靠近硬件(即不要使用 std::mutex
除非它完全满足你的需要)。