您的位置:首页 > 编程语言 > C语言/C++

C++11常用特性学习——多线程优化初步(原子类型/lambda语句)

2015-11-24 20:35 387 查看

C11多线程原子类型

C98/03主要使用互斥等操作来保证线程中数据操作的安全性,这样,数据的修改必须加上thread_mutex等原子锁等来保证数据修改的准确性。有时为了高性能或底层工作,要求线程间的通信没有开销巨大的互斥锁.原子操作可以达到这个目的,这可以随意地为一个操作指定最小的内存可见度。通过
<cstdatomic>
中封装和定义了通用的原子类型,原子类型在通用类型前加atomic_即对应原子类型。如atomic_bool——bool,atomic_int——int,atomic_uint——unsigned int,atomic_llong——long long;

更普遍地,可以使用atomic类模板,通过该类模板,可以任意定义出需要的原子类型:
std::atomic<T> t


对于线程而言,原子类型通常属于资源型”的数据,这意味着多个线程通常只能访问单个原子类型的拷贝。因此在C++中,原子类型只能从其模板参数类型中进行构造,标准不允许原子类型进行拷贝构造、移动构造,以及使用operator=等,以防止发生意外。比如:

atomic<float> af {1.2f};


atomic<float> af1 {af};
//无法编译通过

事实土,atomic模板类的拷贝构造函数、移动构造函数、operator=等总是默认被删除的。《深入理解C++11新特性解析与应用》中第7章有有如何删除一些默认函数的方法。

但是可以:

atomic<int> a;


a = 1;
//,等同于a.store(1)

atomic<int> b;


int c = b;
//,等同于c=b.load()

C11多线程内存模型

主要涉及到内存模型、memory_order等知识点。相关函数:

memory_order_relaxed

memory_order_acquire

memory_oreder_release

memory_order_acq_rel

memory_order_consume

memory_order_seq_cst

关于些 C11在并发编程等方面的新特性和关键知识点:可以参考C++11 并发指南系列 ;

C11的lambda函数

Lambda表达式用于定义并创建匿名的函数对象。java8等已经广泛使用lambda函数形式。C++11页引入了这种模式。Lambda表达式具体形式如下:

[函数对象参数] (操作符重载函数参数) mutable或exception声明 ->返回值类型 {函数体}

[capture](parameters)->return-type{body}


如果没有参数,空的圆括号()可以省略.返回值也可以省略,如果函数体只由一条return语句组成或返回类型为void的话.形如:
[capture](parameters){body}


几个Lambda函数的例子:

[](int x, int y) { return x + y; } // 隐式返回类型
[](int& x) { ++x; }   // 没有return语句 -> lambda 函数的返回类型是'void'
[]() { ++global_x; }  // 没有参数,仅访问某个全局变量
[]{ ++global_x; }     // 与上一个相同,省略了()
[](int x, int y) -> int { int z = x + y; return z; }    //显示指定返回类型:


[capture]捕捉列表。捕捉列表总是出现在lambda函数的开始处。事实上[]是lambda引出符.。编译器根据该引出符判断接下来的代码是否是lambda}函数。捕捉列表能够捕捉上下文中的变量供lambda函数使用。Lambda函数可以引用在它之外声明的变量. 这些变量的集合叫做一个闭包. 闭包被定义在Lambda表达式声明中的方括号[]内. 这个机制允许这些变量被按值或按引用捕获.下面这些例子就是:

[]        //未定义变量.试图在Lambda内使用任何外部变量都是错误的.
[x, &y]   //x 按值捕获, y 按引用捕获.
[&]       //用到的任何外部变量都隐式按引用捕获,(相当于编译器自动为我们按引用传递了所有局部变量)
[=]       //用到的任何外部变量都隐式按值捕获,(相当于编译器自动为我们按值传递了所有局部变量)
[&, x,y]    //x显式地按值捕获. 其它变量按引用捕获,(除X和y按值进行传递外,其他参数都按引用进行传递)
[=, &z]   //z按引用捕获. 其它变量按值捕获,(除z按引用进行传递外,其他参数都按值进行传递。)


和普通函数一样,中间值不会保存到下次调用。什么也不返回的Lambda函数可以省略返回类型, 而不需要使用 -> void 形式。

如:

std::vector<int> some_list;
int total = 0;
for (int i=0;i<5;++i)
some_list.push_back(i);
std::for_each(begin(some_list), end(some_list), [&total](int x)
{
total += x;
});


一般可以用auto表示lambda函数

int main() {
int a =3, b=4;
auto total = [] (int x ,int y)->int{ return x + y};
return total(a,b);
}


上面函数使用传值,可以使用传参数来改写上面函数:

int main() {
int a =3, b=4;
auto total = [a,&b] ()->int{ return a + b};
return total();
}


lambda还支持仿函数的形式;

重载类的operator()函数就能得到一个仿函数的类;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++11