使用C++11的function/bind组件封装Thread以及回调函数的使用

本文介绍了如何使用C++11的function和bind实现线程的回调函数封装,通过类的组合机制简化了线程的创建与使用流程。详细解释了三种线程使用方式:普通函数、类成员函数以及组合线程类,并提供了实例代码演示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前在http://www.cnblogs.com/inevermore/p/4008572.html中采用面向对象的方式,封装了Posix的线程,那里采用的是虚函数+继承的方式,用户通过重写Thread基类的run方法,传入自己的用户逻辑。

 

现在我们采用C++11的function,将函数作为Thread类的成员,用户只需要将function对象传入线程即可,所以Thread的声明中,应该含有一个function成员变量。

类的声明如下:

#ifndef THREAD_H_
#define THREAD_H_

#include <boost/noncopyable.hpp>
#include <functional>
#include <pthread.h>

class Thread : boost::noncopyable
{
public:
    typedef std::function<void ()> ThreadCallback;

    Thread(ThreadCallback callback);
    ~Thread();

    void start();
    void join();

    static void *runInThread(void *);

private:
    pthread_t threadId_;
    bool isRunning_;
    ThreadCallback callback_; //回调函数
};



#endif //THREAD_H_

那么如何开启线程?思路与之前一致,写一个static函数,用户pthread_create的第三个参数,this作为最后一个参数即可。

void Thread::start()
{
    pthread_create(&threadId_, NULL, runInThread, this);
    isRunning_ = true;
}

 

回调函数

 

注意在这种封装方式中,我们采用了回调函数。回调函数与普通函数的区别就是,普通函数写完由我们自己直接调用,函数调用是一种不断往上堆积的方式,而回调函数通常是我们把某一个函数传入一个“盒子”,由该盒子内的机制来调用它。

在这个例子里面,我们将function传入Thread,当Thread启动的时候,由Thread去执行function对象。

在win32编程中大量用到这种机制,我们为鼠标单击、双击等事件编写相应的函数,然后将其注册给windows系统,然后系统在我们触发各种事件的时候,根据事件的类型,调用相应的构造函数。

关于回调函数,可以参考:http://www.zhihu.com/question/19801131

以后有时间,再专门总结下回调函数。

 

完整的cpp如下:

#include "Thread.h"

Thread::Thread(ThreadCallback callback)
: threadId_(0),
  isRunning_(false),
  callback_(std::move(callback))
{

}
    
Thread::~Thread()
{
    if(isRunning_)
    {
        //detach
        pthread_detach(threadId_);
    }
}

void Thread::start()
{
    pthread_create(&threadId_, NULL, runInThread, this);
    isRunning_ = true;
}
void Thread::join()
{
    pthread_join(threadId_, NULL);
    isRunning_ = false;
}

void *Thread::runInThread(void *arg)
{
    Thread *pt = static_cast<Thread*>(arg);
    pt->callback_(); //调用回调函数

    return NULL;
}

 

这个线程的使用方式有三种:

一是将普通函数作为回调函数

void foo()
{
    while(1)
    {
        printf("foo\n");
        sleep(1);
    }
}

int main(int argc, char const *argv[])
{
    Thread t(&foo);

    t.start();
    t.join();

    return 0;
}

 

二是采用类的成员函数作为回调函数:

class Foo
{
public:
    void foo(int i)
    {
        while(1)
        {
            printf("foo %d\n", i++);
            sleep(1);
        }
    }
};


int main(int argc, char const *argv[])
{
    Foo f;
    int i = 34;
    Thread t(bind(&Foo::foo, &f, i));

    t.start();
    t.join();

    return 0;
}

最后一种是组合一个新的线程类,注意这里采用的是类的组合

class Foo
{
public:

    Foo()
    : thread_(bind(&Foo::foo, this))
    {
    }

    void start()
    {
        thread_.start();
        thread_.join();
    }

    void foo()
    {
        while(1)
        {
            printf("foo\n");
            sleep(1);
        }
    }
private:
    Thread thread_;
};

int main(int argc, char const *argv[])
{
    Foo f;
    f.start();

    return 0;
}

有些复杂的类,还需要将三种方式加以整合,例如后面要谈到的TimerThread,里面含有一个Thread和Timer,用户将逻辑注册给Timer,然后Timer的start函数注册给Thread。

这种方式的Thread,使用灵活性相对于面向对象的风格,提高了很多。

 

基于对象和面向对象

 

这里总结几点:

面向对象依靠的是虚函数+继承,用户通过重写基类的虚函数,实现自己的逻辑。

基于对象,依赖类的组合,使用function和bind实现委托机制,更加依赖于回调函数传入逻辑。

转载于:https://www.cnblogs.com/inevermore/p/4038498.html

非常好的问题! 在 C++ 中,使用 `std::function` 作为**回调函数**是一种非常灵活、通用的方式,可以让你在运行时将任意可调用对象(函数、lambda、函数对象等)作为回调传入某个类或函数中。 --- ## ✅ 什么是回调函数? > **回调函数(Callback Function)** 是指在某个事件发生时,由某个函数或对象调用的函数。 例如: - 用户点击按钮时调用一个函数 - 某个任务完成后调用一个通知函数 - 网络请求收到响应后调用处理函数 --- ## ✅ 使用 `std::function` 实现回调函数的优势: - 可以接受任意可调用对象(函数指针、lambda、绑定表达式、函数对象) - 类型安全 - 可以配合 `std::bind` 使用,绑定类成员函数 - 便于封装、扩展和维护 --- ## ✅ 示例:使用 `std::function` 实现一个简单的回调系统 ### 📌 需求: 我们希望实现一个定时器类 `Timer`,它可以在某个时间点触发一个回调函数。 --- ### ✅ 示例代码: ```cpp #include <iostream> #include <functional> #include <thread> #include <chrono> // 定义回调函数类型 using Callback = std::function<void()>; class Timer { public: // 设置回调函数 void setCallback(const Callback& cb) { callback = cb; } // 模拟延迟执行回调 void start(int delay_ms) { std::cout << "Timer started for " << delay_ms << " ms." << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms)); if (callback) { std::cout << "Timer triggered!" << std::endl; callback(); // 执行回调 } } private: Callback callback; }; // 示例回调函数 void myCallback() { std::cout << "This is a normal function callback!" << std::endl; } int main() { Timer timer; // 1. 使用普通函数作为回调 timer.setCallback(myCallback); timer.start(1000); // 2. 使用 Lambda 表达式作为回调 timer.setCallback([]() { std::cout << "Lambda function callback triggered!" << std::endl; }); timer.start(1000); return 0; } ``` --- ## 🧠 代码详解: ### 1. 回调类型定义: ```cpp using Callback = std::function<void()>; ``` - 定义了一个类型别名 `Callback`,表示一个无参数无返回值的可调用对象。 --- ### 2. `Timer` 类: ```cpp class Timer { public: void setCallback(const Callback& cb) { callback = cb; } void start(int delay_ms) { ... callback(); // 调用回调 } private: Callback callback; }; ``` - `setCallback`:设置回调函数 - `start`:模拟延迟后调用回调函数 --- ### 3. 使用回调: ```cpp timer.setCallback(myCallback); // 使用普通函数 timer.setCallback([]() { ... }); // 使用 lambda ``` - `std::function` 可以接受任何符合签名的可调用对象。 --- ## ✅ 输出结果: ``` Timer started for 1000 ms. (等待1秒) Timer triggered! This is a normal function callback! Timer started for 1000 ms. (等待1秒) Timer triggered! Lambda function callback triggered! ``` --- ## ✅ 更高级:绑定类成员函数作为回调 ```cpp class MyClass { public: void callbackMethod() { std::cout << "Member function callback!" << std::endl; } }; int main() { MyClass obj; Timer timer; // 使用 std::bind 绑定成员函数 timer.setCallback(std::bind(&MyClass::callbackMethod, &obj)); timer.start(1000); return 0; } ``` - `std::bind` 可以将类成员函数绑定到特定对象上,变成一个无参函数调用。 --- ## ✅ 总结一句话: > **`std::function` 是实现回调函数的理想选择,它可以统一处理函数指针、lambda、函数对象、成员函数等多种调用方式。** --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值