C/C++编程:pthread_cond_t封装

1059 篇文章 288 订阅

准备

开始

//
// 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()就会一直阻塞

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值