1.boost bind/function
-
boost bind/function库的出现,替代了stl中的mem_fun,ptr_fun,bind1st,bin2nd等函数
-
函数适配器,从一种函数接口适配成另一种接口
-
eg:
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace std;
class Foo
{
public:
//成员函数隐含了第一个参数:Foo*,用于指向对象本身
void memberFunc(double d, int i, int j)
{
cout << d << endl;//打印0.5
cout << i << endl;//打印100
cout << j << endl;//打印10
}
};
int main()
{
Foo foo;
//适配成新接口:void f(int),即:将4个参数的成员函数适配成一个参数的函数
//Void是返回类型,int是形参类型
/*
(1)&foo, 0.5, _1, 10对应于成员函数的4个参数
_1代表占位符,还有_2,_3,表示boost function的参数
(2)相当于调用了:
取地址&foo是一个指针
(&foo)->memberFunc(0.5,100,10)
Boost::bind作用:将一种函数接口转换为另一种类型的函数接口
*/
boost::function<void (int)> fp = boost::bind(&Foo::memberFunc, &foo, 0.5, _1, 10);
fp(100);
return 0;
}
==============================================================================
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace std;
class Foo
{
public:
void memberFunc(double d, int i, int j)
{
cout << d << endl;//打印0.5
cout << i << endl;//打印100
cout << j << endl;//打印10
}
};
int main()
{
Foo foo;
boost::function<void (int, int)> fp = boost::bind(&Foo::memberFunc, &foo, 0.5, _1, _2);
fp(100, 200);
boost::function<void (int, int)> fp2 = boost::bind(&Foo::memberFunc, boost::ref(foo), 0.5, _1, _2);
fp2(55, 66);
return 0;
}
- 注意在std::bind和std::thread中,如果要按照引用进行传递某变量,需要使用std::ref,否则就是值传递即深拷贝,看下面的eg:
#include <iostream>
#include <functional>
#include<vector>
using namespace std;
void f(int& a, int& b, int& c)
{
cout << "in function a = " << a << " b = " << b << " c = " << c << endl;
cout << "in function a = " << &a << " b = " << &b << " c = " << &c << endl;
a += 1;
b += 10;
c += 100;
}
int main() {
int n1 = 1, n2 = 10, n3 = 100;
int& r1 = n1;
int& r2 = n2;
function<void()> f1 = bind(f, r1, r2, ref(n3));
f1();
cout << "out function a = " << n1 << " b = " << n2 << " c = " << n3 << endl;
cout << "out function a = " << &n1 << " b = " << &n2 << " c = " << &n3 << endl;
return 0;
}
- 测试:
in function a = 1 b = 10 c = 100
in function a = 0x505670 b = 0x505674 c = 0x5055a0
out function a = 1 b = 10 c = 200
out function a = 0x5055a8 b = 0x5055a4 c = 0x5055a0
- eg:
#include <iostream>
#include <future>
#include <thread>
int fun(int x, std::promise<int> p) {
x++;
x *= 10;
p.set_value(x);
std::cout << std::this_thread::get_id() << std::endl;
return x;
}
int main()
{
std::promise<int> p;
std::future<int> fu = p.get_future(); // 并将结果返回给future
std::thread t(fun, 1, std::move(p));
std::cout << fu.get() << std::endl; // 当promise还没有值的时候在此等待
std::cout << std::this_thread::get_id() << std::endl;
t.join();
return 0;
}
编译并运行:
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
140324831098624
20
140324831102784
- eg2:Thread类图
typedef boost::function<void ()> ThreadFunc;
2.代码
- 包含的文件有:Thread.h,Thread.cpp,Thread_test.cpp,CMakeLists.txt,build.sh
- Thread.h
#ifndef _THREAD_H_
#define _THREAD_H_
#include <pthread.h>
#include <boost/function.hpp>
class Thread
{
public:
typedef boost::function<void ()> ThreadFunc;//返回类型为void,形参为空
explicit Thread(const ThreadFunc& func);//explicit表示可以显示调用,阻止隐士地转换构造
void Start();
void Join();
void SetAutoDelete(bool autoDelete);
private:
static void* ThreadRoutine(void* arg);
void Run();
ThreadFunc func_;//通过构造函数传递进来
pthread_t threadId_;
bool autoDelete_;
};
#endif // _THREAD_H_
- Thread.cpp
#include "Thread.h"
#include <iostream>
using namespace std;
Thread::Thread(const ThreadFunc& func) : func_(func), autoDelete_(false)
{
}
void Thread::Start()
{
pthread_create(&threadId_, NULL, ThreadRoutine, this);
}
void Thread::Join()
{
pthread_join(threadId_, NULL);
}
void* Thread::ThreadRoutine(void* arg)
{
Thread* thread = static_cast<Thread*>(arg);
thread->Run();
if (thread->autoDelete_)
delete thread;
return NULL;
}
void Thread::SetAutoDelete(bool autoDelete)
{
autoDelete_ = autoDelete;
}
void Thread::Run()
{
func_();
}
- Thread_test.cpp
#include "Thread.h"
#include <boost/bind.hpp>
#include <unistd.h>
#include <iostream>
using namespace std;
class Foo
{
public:
Foo(int count) : count_(count)
{
}
void MemberFun()
{
while (count_--)
{
cout<<"this is a test ..."<<endl;
sleep(1);
}
}
void MemberFun2(int x)
{
while (count_--)
{
cout<<"x="<<x<<" this is a test2 ..."<<endl;
sleep(1);
}
}
int count_;
};
void ThreadFunc()
{
cout<<"ThreadFunc ..."<<endl;
}
void ThreadFunc2(int count)
{
while (count--)
{
cout<<"ThreadFunc2 ..."<<endl;
sleep(1);
}
}
int main(void)
{
//创建线程对象,因为:typedef boost::function<void ()> ThreadFunc;//返回类型为void,形参为空
Thread t1(ThreadFunc);//线程的执行体:ThreadFunc
//下面的不符合接口转化,就用boost::bind进行转化,其返回的函数相当于:boost::function<vid()>
//线程的执行体:ThreadFunc2
Thread t2(boost::bind(ThreadFunc2, 3));//相当于返回了 boost::function<void ()> ,普通函数ThreadFunc2可以省略&符号
Foo foo(3);//MemberFun会执行3次
//线程的执行体:&Foo::MemberFun
Thread t3(boost::bind(&Foo::MemberFun, &foo));//成员函数ThreadFunc2不可以省略&符号,&foo是第一个参数
Foo foo2(3);
Thread t4(boost::bind(&Foo::MemberFun2, &foo2, 1000));
/*
若将Foo foo2(3);注释掉,则:
(&foo)->MemberFun();
(&foo)->MemberFun2();
两个对象随便调用了不同的成员函数,但是都访问了同一个count,相当于2个线程访问了共享变量count,会存在同步问题,两个线程会相互影响
count的值,因为这里的线程不知道谁先谁后运行
*/
//有4个线程
t1.Start();
t2.Start();
t3.Start();
t4.Start();
t1.Join();
t2.Join();
t3.Join();
t4.Join();
return 0;
}
- CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(pas CXX)
set(CXX_FLAGS -g -Wall)
set(CMAKE_CXX_COMPILER "g++")
string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}")
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(Thread_test Thread_test.cpp Thread.cpp)
target_link_libraries(Thread_test pthread)
add_executable(bf_test bf_test.cpp)
- build.sh
#!/bin/sh
set -x
SOURCE_DIR=`pwd`
BUILD_DIR=${BUILD_DIR:-../build}
mkdir -p $BUILD_DIR \
&& cd $BUILD_DIR \
&& cmake $SOURCE_DIR \
&& make $*
3.面向对象编程方法与基于对象的编程方法的区别
- 面向对象编程方法:
EchoServer类继承TcpServer类
当有客户端连接服务端的时候,网络库net的EventLoop会调用TcpServer类中的纯虚函数OnConnection,
app提供了EchoServer类,他实现了Onconnection,OnMessage,Onclose这3个方法,
当事件被网络库捕捉到的时候,TcpServer会回调上述的3个方法(基类指针指向派生类对象,调用派生类的虚函数),通过虚函数的回调方法
- 基于对象的编程方法
将成员函数进行bind,当网络库收到事件后,都会回调下面三个成员函数
为啥叫基于对象?因为用到了class,底层还是回调了成员函数
class EchoServer
{
public:
EchoServer()
{
server.SetConnectionCallback(boost::bind(onConnection));
server.SetConnectionCallback(boost::bind(onConnection));
server.SetConnectionCallback(boost::bind(onConnection));
}
void onConnection(){}
void onMessage()
void onClose
TcpServer server
}
- 总结:
(1)如果用C语言写的话,就是注册三个全局函数到网络库,网络库通过函数指针来回调
(2)面向对象风格,是用一个EchoServer继承抽象类TcpServer,实现3个接口Onconnection,OnMessage,Onclose
(3)基于对象风格,用一个EchoServer包含一个具体类Tcpserver对象,在构造函数中用boost::bind来注册3个成员函数Onconnection,OnMessage,Onclose