准备
开始
//
// Created by oceanstar on 2021/8/9.
//
#ifndef OCEANSTAR_HTTP_THREAD_COND_H
#define OCEANSTAR_HTTP_THREAD_COND_H
#include <noncopyable.h>
#include <cstdio>
#include "thread_mutex.h"
namespace oceanstar{
//class thread_mutex;
/**
* 线程条件变量
*/
class thread_cond : public noncopyable{
public:
/**
* 构造方法
* @param mutex {thread_mutex*} 当该参数非 NULL 时,内部自动引用
* 该线程锁,否则,内部创建线程锁
*/
thread_cond(thread_mutex* mutex = NULL);
~thread_cond(void);
/**
* 等待线程条件变量就绪
* @param microseconds {long long} 等待条件变量就绪的超时时间(微秒级)
* > 0 时表示等待超时的时间
* == 0,不等待
* < 0 则一直等待直到条件变量就绪
* @param locked {bool} 该参数表明是否已经将锁加锁,如果还未加锁,则
* 内部会先自动加锁,方法返回前再解锁;如果外部已经加锁,则内部不对
* 互斥锁做加锁/解锁处理
* @return {bool} 返回 true 表示条件变量就绪,否则表示超时或没被通知
*/
bool wait(long long microseconds = -1, bool locked = false);
/**
* 通知一个或几个等待在线程条件变量上的线程,表示条件变量就结
* @return {bool} 返回 false 表示通知失败
*/
bool notify(void);
/**
* 通知所有等待在线程条件变量上的线程,表示条件变量就结
* @return {bool} 返回 false 表示通知失败
*/
bool notify_all(void);
/**
* 获得与该线程条件变量绑定的线程互斥锁
* @return {thread_mutex&}
*/
thread_mutex& get_mutex(void) const;
/**
* 获得系统类型的线程条件变量对象
* @return {acl_pthread_cond_t*}
*/
pthread_cond_t* get_cond(void) const;
private:
thread_mutex* mutex_;
thread_mutex* mutex_internal_;
pthread_cond_t* cond_;
bool block_wait(bool locked);
bool timed_wait(long long microseconds, bool locked);
};
}
#endif //OCEANSTAR_HTTP_THREAD_COND_H
//
// Created by oceanstar on 2021/8/9.
//
#include <errno.h>
#include <sys/time.h>
#include "thread_cond.h"
#include "thread.h"
namespace oceanstar{
thread_cond::thread_cond(thread_mutex* mutex)
{
if (mutex) {
mutex_internal_ = NULL;
mutex_ = mutex;
} else {
mutex_internal_ = new thread_mutex;
mutex_ = mutex_internal_;
}
cond_ = (pthread_cond_t*)calloc(1, sizeof(pthread_cond_t));
pthread_cond_init(cond_, NULL);
}
thread_cond::~thread_cond(void)
{
pthread_cond_destroy(cond_);
free(cond_);
delete mutex_internal_;
}
bool thread_cond::notify(void)
{
return pthread_cond_signal(cond_) == 0;
}
bool thread_cond::notify_all(void)
{
return pthread_cond_broadcast(cond_) == 0;
}
thread_mutex& thread_cond::get_mutex(void) const
{
return *mutex_;
}
pthread_cond_t* thread_cond::get_cond(void) const
{
return cond_;
}
bool thread_cond::wait(long long microseconds /* = -1 */,
bool locked /* = false */)
{
if (microseconds >= 0) {
return timed_wait(microseconds, locked);
} else {
return block_wait(locked);
}
}
bool thread_cond::block_wait(bool locked)
{
bool locked_internal;
if (!locked) {
if (!mutex_->lock()) {
logger_error("lock error=%s", strerror(errno));
return false;
}
locked_internal = true;
} else {
locked_internal = false;
}
int ret = pthread_cond_wait(cond_, mutex_->get_mutex());
if (ret) {
logger_error("pthread_cond_wait error %s", strerror(errno));
}
// 如果本方法内部前面加了锁,则此处需要解锁
if (locked_internal && !mutex_->unlock()) {
logger_error("mutex unlock error=%s", strerror(errno));
return false;
}
return ret == 0 ? true : false;
}
#define SEC_TO_NS 1000000000 // nanoseconds per second
#define SEC_TO_MIS 1000000 // microseconds per second
#define MIS_TO_NS 1000 // nanoseconds per microseconds
bool thread_cond::timed_wait(long long microseconds, bool locked)
{
struct timeval tv;
gettimeofday(&tv, NULL);
struct timespec ts;
ts.tv_sec = (time_t) (tv.tv_sec + microseconds / SEC_TO_MIS);
long long n = (tv.tv_usec + microseconds % SEC_TO_MIS) * MIS_TO_NS;
ts.tv_nsec = (long) n % SEC_TO_NS;
ts.tv_sec += (long) n / SEC_TO_NS;
bool locked_internal;
if (mutex_internal_ || !locked) {
if (!mutex_->lock()) {
logger_error("lock error=%s", strerror(errno));
return false;
}
locked_internal = true;
} else {
locked_internal = false;
}
int ret = pthread_cond_timedwait(cond_, mutex_->get_mutex(), &ts);
if (ret) {
if (ret != ETIMEDOUT) {
logger_error("pthread_cond_timedwait error=%s", strerror(errno));
}
}
if (locked_internal && !mutex_->unlock()) {
logger_error("mutex unlock error=%s", strerror(errno));
return false;
}
return ret == 0 ? true : false;
}
}
测试
#include "mythread/thread_cond.h"
#include <unistd.h>
#include "thread.h"
class mythread3 : public oceanstar::thread
{
public:
mythread3(oceanstar::thread_cond& cond) : cond_(cond) {}
~mythread3(void) {}
protected:
void* run(void)
{
int i = 0;
while (i++ < 5)
{
printf("sleep one second\r\n");
sleep(1);
}
cond_.notify();
return NULL;
}
private:
oceanstar::thread_cond& cond_;
};
int main() {
oceanstar::thread_cond cond;
mythread3 thread(cond);
thread.start();
printf("wait %s\r\n", cond.wait() ? "ok" : "error");
return 0;
}
这个函数是有缺陷的,如果在调用cond.wait()
之前,cond_.notify()
就已经发出了,那么cond.wait()就会一直阻塞