c+++11并发编程语言,C++ 11 并发编程学习记录

文章目录

1、join,detach区别

2、临时变量传值

2.1、一般类型引用传值正确

2.2 类构造函数使用引用参数错误

2.3 隐式转换传值错误

3、减少一次拷贝

3.1 使用std::ref()函数

3.2 使用智能指针

4、lock、unlock、lock_guard的使用

1、join,detach区别

join:表示将子线程加入父线程,当子线程运行完,才运行父线程,一般情况下使用这个函数,出错的概率小

detach:表示父子线程分离,分离后子线程由守护线程管理,内存清理工作等等都是在后台进行,所以问题会很多,慎用

两个函数不能同时使用,可以使用joinable()函数来判断是否已经进行过join 或者detach了

运行下面代码看看结果

#include #include using namespace std;

class newClass {

private:

int t_a;

public:

newClass(int a) :t_a(a) {

cout << "构造函数" << endl;

}

newClass(const newClass &tmp) :t_a(tmp.t_a) {

cout << "拷贝构造函数" << endl;

}

~newClass() {

cout << "析构函数" << endl;

}

void operator ()() {

cout << "test 1: " << t_a << endl;

cout << "test 2: " << t_a << endl;

cout << "test 3: " << t_a << endl;

cout << "test 4: " << t_a << endl;

cout << "test 5: " << t_a << endl;

}

};

int main()

{

int c = 23;

newClass t(c);

thread myobj(t);

if (myobj.joinable()) {

cout << "thread joinable true" << endl;

//myobj.detach();

myobj.join();

}

cout << "main thread 1" << endl;

cout << "main thread 2" << endl;

cout << "main thread 3" << endl;

cout << "main thread 4" << endl;

return 0;

}

下图表示join函数的运行结果,需要子线程运行完后才运行父线程,顺序跟代码的顺序固定

163f1aae082a4675a5fd50351137fd57.png

下图表示detach函数运行的结果,很混乱

1f0b2ac344244918b3c81039e79d5538.png

2、临时变量传值

2.1、一般类型引用传值正确

//这个是正确的,我们可以调试看到a num是不同的地址的,可见,thread类会将数据进行拷贝一次

#include #include using namespace std;

void testFunction(const int &a) {

cout << "the int is: " << a << endl;

}

int main()

{

int num = 7;

thread myobj(testFunction, num);

if (myobj.joinable()) {

myobj.detach();

}

return 0;

}

80282c9fac5c42a286a36685c8b150fc.jpg

2.2 类构造函数使用引用参数错误

/*

下面代码使用detach

子线程使用的是主线程的局部变量的引用,所以有可能提前析构了这个局部变量,导致子线程无法使用对应的对象

可能会出现如下截图的结果

*/

#include #include using namespace std;

class newClass {

private:

int *t_a;

public:

newClass(int* a) :t_a(a) {

cout << "构造函数" << endl;

}

newClass(const newClass &tmp) :t_a(tmp.t_a) {

cout << "拷贝构造函数" << endl;

}

~newClass() {

cout << "析构函数" << endl;

}

void operator ()() {

cout << "test 1: " << *t_a << endl;

cout << "test 2: " << *t_a << endl;

cout << "test 3: " << t_a << endl;

cout << "test 4: " << t_a << endl;

cout << "test 5: " << t_a << endl;

}

};

int main()

{

int c = 23;

newClass t(&c);

thread myobj(t);

if (myobj.joinable()) {

myobj.detach();

//myobj.join();

}

cout << "main thread 1" << endl;

cout << "main thread 2" << endl;

cout << "main thread 3" << endl;

cout << "main thread 4" << endl;

return 0;

}

b803c0d3a88c441da69cb55b0df21593.png

2.3 隐式转换传值错误

//下面代码中,如果将注释打开,或许可以看得到hello world 的打印结果

//因为是使用了临时变量,可能是被销毁了,这个是比较基本的C++语法

#include #include using namespace std;

void testFunction(const char *str) {

cout << "the str is: " << str << endl;

}

int main()

{

thread myobj(testFunction,"hello world");

if (myobj.joinable()) {

myobj.detach();

}

/*cout << "main thread 1" << endl;

cout << "main thread 2" << endl;

cout << "main thread 3" << endl;

cout << "main thread 4" << endl;*/

return 0;

}

//下面代码使用string进行隐式转换同样会出现一样的问题,可以自己尝试运行一下代码,以及下面注释的代码

#include #include using namespace std;

void testFunction(string str) {

cout << "the str is: " << str.c_str() << endl;

}

int main()

{

const char* mystr = "hello world";

thread myobj(testFunction, mystr);

if (myobj.joinable()) {

myobj.detach();

}

/*cout << "main thread 1" << endl;

cout << "main thread 2" << endl;

cout << "main thread 3" << endl;

cout << "main thread 4" << endl;*/

return 0;

}

//解决办法:显示转换即可

thread myobj(testFunction, string("hello world"));

下面代码中的

thread myobj(testFunction, newClass(8));

newClass就是string类,数字8就是代表hello world

通过显示转换,运行代码可以看得到有两次构造,一次使用赋值构造,一次使用拷贝构造(thread对象会进行拷贝一次)

验证代码:发现构建临时变量的时候是在主线程中进行的

注意:这里传递类变量的时候,函数中使用引用来接受数据,可以减少一次构建

否则多出来的一次构建又到子线程中去了,可能会导致某些问题

#include #include using namespace std;

class newClass {

public:

int t_a;

newClass(int a) :t_a(a) {

cout << "构造函数 " << this << " 线程 " << this_thread::get_id() << endl;

}

newClass(const newClass &tmp) :t_a(tmp.t_a) {

cout << "拷贝构造函数 " << this << " 线程 " << this_thread::get_id() << endl;

}

~newClass() {

cout << "析构函数 " << endl;

}

};

void testFunction(const newClass& tmp) {

cout << "the str is: " << " 线程 " << this_thread::get_id() << tmp.t_a << endl;

}

int main()

{

cout << "主线程 " << this_thread::get_id() << endl;

thread myobj(testFunction, newClass(8));

if (myobj.joinable()) {

myobj.detach();

}

return 0;

}

3、减少一次拷贝

一旦少了一次拷贝,很明显,此时一定要使用join函数,如果使用detach这个时候回出现主线程退出了,子线程还在工作的情况,造成内存泄漏

3.1 使用std::ref()函数

传递引用就可以少一次拷贝

#include #include using namespace std;

class newClass {

public:

int t_a;

newClass(int a) :t_a(a) {

cout << "构造函数 " << this << " 线程 " << this_thread::get_id() << endl;

}

newClass(const newClass &tmp) :t_a(tmp.t_a) {

cout << "拷贝构造函数 " << this << " 线程 " << this_thread::get_id() << endl;

}

~newClass() {

cout << "析构函数 " << endl;

}

};

void testFunction(const newClass& tmp) {

cout << "the str is: " << " 线程 " << this_thread::get_id() << tmp.t_a << endl;

}

int main()

{

newClass myclass(80);

cout << "主线程 " << this_thread::get_id() << endl;

thread myobj(testFunction, std::ref(myclass));

if (myobj.joinable()) {

myobj.join();

}

return 0;

}

3.2 使用智能指针

#include #include using namespace std;

class newClass {

public:

int t_a;

newClass(int a) :t_a(a) {

cout << "构造函数 " << this << " 线程 " << this_thread::get_id() << endl;

}

newClass(const newClass &tmp) :t_a(tmp.t_a) {

cout << "拷贝构造函数 " << this << " 线程 " << this_thread::get_id() << endl;

}

~newClass() {

cout << "析构函数 " << endl;

}

};

void testFunction(unique_ptrtmp) {

cout << "the str is: " << " 线程 " << this_thread::get_id() << tmp->t_a << endl;

}

int main()

{

unique_ptra(new newClass(10));

cout << "主线程 " << this_thread::get_id() << endl;

thread myobj(testFunction, std::move(a));

if (myobj.joinable()) {

myobj.join();

}

return 0;

}

4、lock、unlock、lock_guard的使用

//模板lock_guard是在构造函数调用lock函数,在析构的时候调用unlock函数

#include #include #include #include using namespace std;

class newClass {

public:

void ProcessOne() {

for (int i = 0; i < 100; i++) {

std::lock_guardt_gd(my_mutex1);

num.push_back(i);

cout << "One One One One" << endl;

}

}

void ProcessTwo() {

for (int i = 0; i < 100; i++) {

my_mutex1.lock();

if (!num.empty()) {

num.pop_front();

}

cout << "Two Two Two " << endl;

my_mutex1.unlock();

}

}

private:

listnum;

mutex my_mutex1, my_mutex2;

};

int main()

{

newClass tmp;

thread myobj1(&newClass::ProcessOne, std::ref(tmp));

thread myobj2(&newClass::ProcessTwo, std::ref(tmp));

myobj1.join();

myobj2.join();

return 0;

}

如果是多个锁,那么需要很多个lock与unlock,需要我们很细心的去写,并且实际项目中也建议这样子写,但是还是有另外的一种方便的方式,作为备用,其中std::adopt_lock表示标记已经锁上了

#include #include #include #include using namespace std;

class newClass {

public:

void ProcessOne() {

for (int i = 0; i < 100; i++) {

std::lock(my_mutex1, my_mutex2);

std::lock_guardt_gd1(my_mutex1, std::adopt_lock);

std::lock_guardt_gd2(my_mutex2, std::adopt_lock);

num.push_back(i);

cout << "One One One One" << endl;

}

}

void ProcessTwo() {

for (int i = 0; i < 100; i++) {

std::lock(my_mutex1, my_mutex2);

std::lock_guardt_gd1(my_mutex1, std::adopt_lock);

std::lock_guardt_gd2(my_mutex2, std::adopt_lock);

if (!num.empty()) {

num.pop_front();

}

cout << "Two Two Two " << endl;

}

}

private:

listnum;

mutex my_mutex1, my_mutex2;

};

int main()

{

newClass tmp;

thread myobj1(&newClass::ProcessOne, std::ref(tmp));

thread myobj2(&newClass::ProcessTwo, std::ref(tmp));

myobj1.join();

myobj2.join();

return 0;

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值