bosthhe1 / cpushpush

0 stars 0 forks source link

function+bind+thread+ref() #46

Open bosthhe1 opened 1 year ago

bosthhe1 commented 1 year ago

包装器的书写新式 对于普通函数,仿函数的包装是这样的: image 对于类成员函数的包装

class A
{
public:
    int f4(int a, int b)
    {
        return a + b;
    }
    static int f5(int a, int b)
    {
        return a - b;
    }
};

1.非静态成员函数

    function<int(A, int, int)> func4= &A::f4;//注意必须将A类型传过去,因为要调用f4,必须通过实例化对象调用,必须指定A域下的f4,并取地址
    cout<<func4(A(), 1, 2)<<endl;//使用A的匿名对象调用

image

2.静态成员函数

    function<int(int, int)> func5 = &A::f5;//静态成员函数就不需要使用实例化调用,可以直接调用
    cout<<func5(1, 2)<<endl;

image

bosthhe1 commented 1 year ago

包装器是为了防止模板实例化出多份而设计的,具体底层原理不太清楚 没有包装器,模板被实例化出三份

double f1(double x)
{
    return x / 2;
}
struct f2
{
    double operator()(double x)
    {
        return x / 3;
    }
};
auto f3 = [](double x){return x / 4; };
template<class F,class T>
void func(F f, T x)
{
    static int  a = 1;
    cout << &a << endl;
    f(x);
}
int main()
{
    func(f1, 1.1);
    func(f2(), 1.1);
    func(f3, 1.1);
    return 0;
}

image

bosthhe1 commented 1 year ago

有包装器模板就只实例化出一份

double f1(double x)
{
    return x / 2;
}
struct f2
{
    double operator()(double x)
    {
        return x / 3;
    }
};
auto f3 = [](double x){return x / 4; };
template<class F,class T>
void func(F f, T x)
{
    static int  a = 1;
    cout << &a << endl;
    f(x);
}
int main()
{
    function<double(double)> func1 = f1;
    func(func1, 1.1);
    function<double(double)> func2 = f2();
    func(func2,1.1);
    function<double(double)> func3 = f3;
    func(func3, 1.1);
    return 0;
}

image

bosthhe1 commented 1 year ago

bind是搭配function使用的,bind的可以调换参数传递顺序,在调用成员函数的时候,也可以一劳永逸的传递匿名对象 bind的写法

int func5(int a, int b)
{
    return a - b;
}
int main()
{
    function<int(int, int)> f1 = bind(func5, placeholders::_1, placeholders::_2);//这里面的_1,_2就是传参顺序,如果将顺序颠倒,那么传参也会颠倒。
    cout << f1(1, 2) << endl;;
    function<int(int, int)> f2 = bind(func5, placeholders::_2, placeholders::_1);//这里颠倒1,2
    cout << f2(1, 2) << endl;
}

image

bosthhe1 commented 1 year ago
class F
{
public:
    int func1(int a, int b)
    {
        return a - b;
    }
    static int func2(int a, int b)
    {
        return a - b;
    }
};
int main()
{
    function<int(int, int)> f1 = bind(&F::func1,F(), placeholders::_1, placeholders::_2);
    cout << f1(1, 2) << endl;
    function<int(int, int)> f2 = bind(&F::func2, placeholders::_1, placeholders::_2);
    cout << f2(1, 2) << endl;
    return 0;
}

9 Z}WH}P9PV0{3KKW}@WB7

bosthhe1 commented 1 year ago

thread:初始化 image 传一个方法

int main()
{
    mutex mtx;
    int x = 0;
    thread pt1([&]{//直接使用lambda表达式来使用,记得上锁
        mtx.lock();
        for (int i = 0; i < 1000000; i++)
        {
            x++;
        }
        mtx.unlock();
    });
    thread pt2([&]{
        mtx.lock();
        for (int i = 0; i < 1000000; i++)
        {
            x++;
        }
        mtx.unlock();
    });
    pt1.join();
    pt2.join();
    cout << x << endl;
    return 0;
}

传两个参数

#include<thread>
#include<mutex>
int x = 0;
mutex mtx;
void func1(int n)
{
    mtx.lock();//这里封装到外面为串行,不能体现出并行,但是在这个场景下,锁在外面既安全,又能提高效率,
//如果锁写在for循环里面,会造成频繁切换恢复上下文,造成效率低下的问题
    for (int i = 0; i < n; i++)
    {
        x++;
    }
    mtx.unlock();
}

int main()
{
    thread pt1(func1, 1000000);
    thread pt2(func1, 1000000);
    pt1.join();
    pt2.join();
    cout << x << endl;
    return 0;
}
bosthhe1 commented 1 year ago

c++11中对于一些简单的++或者--都有一个类进行封装,将其变为原子性的

#include<thread>
#include<atomic>
atomic<int> x = 0;//atomic<int>封装过的x的一些简单操作变为原子性的
void func1(int n)
{
    for (int i = 0; i < n; i++)
    {
        x++;//由于封装过的x++为原子性,所以不用上锁
    }
}

int main()
{
    thread pt1(func1,10000000);
    thread pt2(func1, 10000000);
    pt1.join();
    pt2.join();
    cout << x << endl;
    return 0;
}

image

bosthhe1 commented 1 year ago

在线程引用传参的时候,必须使用ref函数传参,如果不调用ref函数传参,对于内置类型和自定义类型会调用传值传参的方式进行传参,不会报错,但是对于mtx传参,会报错 我们发现对于ref传参的b地址一样,但是对于没有ref传参的a,地址不一样 image