我正在尝试锁定 ESP32。显然,实现锁有不同的方式:
#include <mutex>
std::mutex mtx;
mtx.lock();
mtx.unlock();
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
xSemaphoreTake(xMutex, portMAX_DELAY);
xSemaphoreGive(xMutex);
是否存在我应该注意的根本差异?
或者它们是等价的?
最佳答案
假设您使用的是 ESP-IDF SDK,该工具链基于 GCC 5.2,针对 xtensa-lx106 指令集,带有部分开源的 C 运行时库。
GNU libstdc++ 中的 std::mutex
委托(delegate)给 pthread_mutex_lock/unlock 调用。 ESP-IDF SDK 包含一个 pthread emulation layer ,我们可以在其中看到 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;
}
如您所见,它主要将调用委托(delegate)给 RTOS 信号量 API,并进行一些额外的检查。
您可能不需要/想要这些检查。考虑到 esp32 芯片的微小 i-cache 和极其缓慢的串行 RAM,我更愿意尽可能靠近硬件(即不要使用
std::mutex
,除非它完全满足您的需要)。关于c++ - C++ mutex 和 RTOS xMutex 的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57430102/