CLOCK_MONOTONIC and pthread_mutex_timedlock / pthread_cond_t
CLOCK_MONOTONIC and pthread_mutex_timedlock / pthread_cond_timedwait
pthread_mutex_timmedlock文档说abs_timeout
接受一个CLOCK_REALTIME
。然而,我们都知道,它不适合为特定的持续时间计时(由于系统时间调整)。
是否有一种方法可以使pthread锁定超时在CLOCK_MONOTONIC
上是可移植的?pthread_cond_timedwait也是如此。
看了文档和pthread.h
之后,我找不到让pthread_mutex_timmedlock使用CLOCK_MONOTONIC
的方法,所以我认为这(目前)是不可能的。但是,对于pthread_cond_timedwait,可以使用如下代码:
pthread_condattr_t attr;
pthread_cond_t cond;
/* ... */
pthread_condattr_init(&attr);
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
pthread_cond_init(&cond, &attr);
为了清楚起见,我省略了错误代码检查,但当然你应该这样做。
我假设使用CLOCK_REALTIME
是因为它总是可用的,而原则上CLOCK_MONOTONIC
是可选的。另外,我想知道设置绝对超时是否可以在系统调用被信号等中断后更容易恢复。
然而,它似乎相当不一致,时钟可以设置在某些情况下,而不是其他-真的应该有一个pthread_mutexattr_setclock()
,但唉,似乎没有一个。我猜你只能祈祷没人定钟了!
在OS X和FreeBSD上,你可以使用kqueue
和kevent
。看我的答案在这里:https://stackoverflow.com/a/31174803/432
在GLIBC中还没有办法改变pthread_mutex_timmedlock的时钟。可能是由于向后兼容的原因,MONOTONIC时钟比REALTIME引入得晚,所以有很多软件都在使用这个功能,更换clock可能会对这个有影响。
Linux的解决方案:
- 你可以在这里找到pthread_mutex_timelock的源代码,它是基于FUTEX的系统调用,默认使用MONOTONIC。因此,您可以使用本文实现自己的互斥锁,这可能是一个很好的健壮的解决方案。
今天我发现了另一个可能的选择(对于Cpp),使用timed_mutex这样的:
timed_mutex m_wait;
if (m_wait.try_lock_for(std::chrono::milliseconds(tout))) return 0;
return -1; // timeout
https://cplusplus.com/reference/mutex/timed_mutex/try_lock_for/我想我解决了这个问题,用一个变通的代码。我在linux (c++)中使用了这个代码
myMutex.cpp
struct myMutexW_s {
std::mutex m_wait;
std::mutex m_thw;
pthread_t tWId = 0;
uint32_t tout = 1;
};
void Aux_Millisleep(int ms) {
if (ms > 0) {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = ms * 1000;
select(0, NULL, NULL, NULL, &tv);
}
}
static void* myWait_ThFcn(void* arg) {
myMutexW_ts* m_ = (myMutexW_ts*)arg;
pthread_detach(pthread_self());
int s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (s != 0) { printf("pthread_setcancelstate: FAIL %d, %Xn", s, m_); }
s = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (s != 0) { printf("pthread_setcanceltype: FAIL %d, %Xn", s, m_); }
m_->m_thw.lock();
Aux_Millisleep(m_->tout);
m_->m_wait.unlock();
m_->tWId = 0;
return nullptr;
}
int myMutexTryLock(myMutexW_ts* m_) {
return m_->m_wait.try_lock();
}
int myMutexWaitms(uint32_t tms, bool CrlI, myMutexW_ts* m_) {
if (tms <= 0) return -1; // "timeout"
if (m_ == nullptr) return -10;
if (CrlI) m_->m_wait.try_lock();
m_->m_thw.try_lock();
m_->tout = tms;
if ((ret = pthread_create(&m_->tWId, nullptr, &myWait_ThFcn, m_)) == 0) {
pthread_yield();
} else {
printf("myMutexWaitms: FAIL %X, r:%d, th:%d, to:%dn",
m_, ret, m_->tWId, m_->tout);
Aux_Millisleep(m_->tout); // fake timeout
return -20; // !!!!!!
}
m_->m_thw.unlock();
m_->m_wait.lock();
if (m_->tWId) {
pthread_cancel(m_->tWId);
return 0; // unlocked before timeout
}
return -1; // timeout
}
void myMutexUnlock(myMutexW_ts* m_) {
if (m_ == nullptr) return;
m_->m_wait.unlock();
}
myMutexW_ts* myMutexNew(void) {
return new myMutexW_ts;
}
void myMutexDel(myMutexW_ts** m_) {
if (m_) {
if (*m_) {
if ((*m_)->tWId) {
pthread_cancel((*m_)->tWId);
(*m_)->tWId = 0;
(*m_)->m_wait.unlock();
}
delete (*m_);
}
(*m_) = nullptr;
}
}
myMutex.h
#include <stdint.h>
#include <stdbool.h>
typedef struct myMutexW_s myMutexW_ts;
#ifdef __cplusplus
extern "C" {
#endif
int myMutexTryLock(myMutexW_ts* m_) ;
int myMutexWaitms(uint32_t tms, bool CrlI, myMutexW_ts* m_);
void myMutexUnlock(myMutexW_ts* m_) ;
myMutexW_ts* myMutexNew(void);
void myMutexDel(myMutexW_ts** m_);
#ifdef __cplusplus
}
#endif
用法与普通互斥锁类似。
我还在测试它的性能,但显然它表现得很好。
- 在 c++11 中为 pthread 设置调度参数
- 如果不包含 pthread,为什么 GCC 的线程标准库实现会抛出异常?
- pthread只有在线程数量较少时才可以正常工作
- pthread执行时间比顺序执行时间差
- 使用 -pthread 如何不违反 ODR 规则?
- 使用 pthread 的多线程
- 销毁 pthread 互斥体和 C++ 中的取消初始化顺序
- 函数 AfxEndThread 中的读取访问冲突"pThread-> was nullptr"
- 锁定步进pthread互斥
- Pthread段错误,使用指向main中变量的指针
- pthread导致的内存泄漏
- GCC:--静态链接到pthread的整个存档配方在最近的GCC版本中停止工作
- 正确地编写一个类,并将pthread与vlc库和c++一起使用
- 直接读取 pthread 互斥锁的所有者字段是否安全?
- 为什么 pthread 会减慢代码速度?
- 对 pthread CLion 的未定义引用
- C++ 17:pthread的生成文件标志
- 将带有结构的参数传递给 pthread
- Posix 线程类和启动例程 (pthread)
- 在 pthread 中使用共享变量