C++多线程1(复习向笔记)

创建线程以及相关函数

当用thread类创建线程对象绑定函数后,该线程在主线程执行时就已经自动开始执行了,join起到阻塞主线程的作用

#include <iostream>
#include <thread>
#include <string>
using namespace std;
//测试函数
void printString(string str)
{cout << str << endl;
}
int main()
{//创建线程,需要包括thread头文件,构造函数后续参数里可选,放入线程绑定函数的参数thread thread1(printString,"Hello World!");//joinable函数,有些线程不一定能用join或者detach,joinable返回一个布尔值,true时使用join增加严谨性bool flag = thread1.joinable();if (flag)thread1.join();//主程序等待线程执行完毕,不加join可能会导致线程绑定的函数没执行完,主程序就结束了//分离主线程和子线程,会可能导致子线程还未执行完毕,主线程就结束了/*thread1.detach();*/return 0;
}

使用detach输出结果,一般使用较少
在这里插入图片描述
更直观的join和joinable的例子

#include <iostream>
#include <thread>
using namespace std;void display()
{for (int i = 0; i < 100; i++)cout << i << " ";cout << endl << "子线程结束" << endl;
}int main()
{thread thread1(display);bool flag = thread1.joinable();if (flag)thread1.join();cout << "主线程结束" << endl;return 0;
}

输出
不难发现,主线程阻塞在了join中,等待子线程执行完毕,再往下执行

常见问题以及解决方法

一般注意变量的声明周期即可

绑定函数的参数为引用

使用ref()函数

#include <iostream>
#include <thread>
using namespace std;void test01(int& a)
{a += 1;
}
int main()
{int a = 11;//绑定函数时参数,传递引用时需要用std下的ref函数将变量转换为引用类型,否则thread无法判断为引用类型thread thread1(test01, ref(a));if (thread1.joinable())thread1.join();cout << a << endl;return 0;
}

在这里插入图片描述
错误例子,运行结果报错,也有可能不报错
错误原因,在本例中,a不在main中,函数执行完后内存会释放掉,由于是线程模式,test01和test02的执行速度不一致,有可能在test02执行完后,test01还没有执行完,所以导致了空指针异常!
解决方法:将a变成局部变量

#include <iostream>
#include <thread>
using namespace std;
thread thread1;
void test01(int& a)
{a += 1;
}void test02()
{int a = 11;//绑定函数时参数,传递引用时需要用std下的ref函数将变量转换为引用类型,否则thread无法判断为引用类型thread1 = thread(test01, ref(a));
}
int main()
{test02();if (thread1.joinable())thread1.join();return 0;
}

指针提前释放

//指针案例
void test03(int* a)
{cout << "*a = " << * a << endl;
}
int main()
{int* p = new int(1);thread thread1(test03,p);//在join之前手动释放了指针,指针指向的空间值变成了随机值delete p;if (thread1.joinable())thread1.join();return 0;
}

在这里插入图片描述

类成员函数作为线程函数,但对象被提前释放

其实跟指针的报错差不多,注意在join()之前不要释放对象即可
智能指针可以减少在join()之前手动释放的问题,它会自动调用析构函数自己销毁对象
整体源代码

#include <iostream>
#include <thread>
#include <memory>
using namespace std;
//引用案例
void test01(int& a)
{a += 1;
}
//指针案例
void test03(int* a)
{cout << "*a = " << * a << endl;
}
//类案例
class A {
public:void func(){cout << "类成员函数作为线程函数" << endl;}
};
int main()
{A a;//类成员函数作为线程函数时,需要用&来制定成员函数的地址,同时还需要传递指针/引用thread thread1(&A::func,&a);thread1.join();//智能指针,已经是指针了shared_ptr<A> b = make_shared<A>();//直接传入值即可thread thread2(&A::func, b);thread2.join();return 0;
}

在这里插入图片描述

互斥锁解决变量访问互质问题

学过OS这部分就很容易理解了
只是C++具体实现罢了,具体看代码
线程安全:如果多线程程序每一次运行的结果跟单线程程序运行的结果是一样的,那么就称这个线程是安全的

#include <iostream>
#include <thread>
#include<mutex>
using namespace std;
mutex mtx;
int a = 0;
void add()
{for (int i = 0; i < 1000; i++){//上锁相当于P(mutex)mtx.lock();a++;//解锁相当于V(mutex)mtx.unlock();}}
int main()
{//创建两个线程thread thread1(add);thread thread2(add);thread1.join();thread2.join();//输出共享变量cout << a << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/437921.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

进阶-宏观.总体(二)失业、利率,税收、物价、供给侧政策、汇率

32&#xff0e;经济的跷跷板之一&#xff1a;成长与失业 失业是任何一个社会都会发生的现象。从某个观点来说&#xff0c;一定程度内的失业是正常的&#xff0c;也应是社会中被允许发生的现象&#xff1b;它是社会中正常的新陈代谢&#xff0c;也可能是社会进步的必然。 分析四…

《HTML 简易速速上手小册》第6章:HTML 语义与结构(2024 最新版)

文章目录 6.1 语义化标签的重要性6.1.1 基础知识6.1.2 案例 1&#xff1a;使用 <article>, <section>, <aside>, <header>, 和 <footer>6.1.3 案例 2&#xff1a;构建带有嵌套语义化标签的新闻网站6.1.4 案例 3&#xff1a;创建一个带有 <mai…

力扣题目训练(3)

2024年1月27日力扣题目训练 2024年1月27日力扣题目训练290. 单词规律292. Nim 游戏303. 区域和检索 - 数组不可变91. 解码方法92. 反转链表 II41. 缺失的第一个正数 2024年1月27日力扣题目训练 2024年1月27日第三天编程训练&#xff0c;今天主要是进行一些题训练&#xff0c;包…

node后端服务框架

前言&#xff1a; 随着互联网的快速发展&#xff0c;Web 开发已成为当今计算机领域中非常重要的一部分。 Node.js 的出现为前端开发者提供了一个全新的方向&#xff0c;使得他们可以同时涉足前端和后端开发。Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时&#xff…

sqli.labs靶场(第18~22关)

18、第十八关 经过测试发现User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0加引号报错 这里我们闭合一下试试 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0,127.0.0.1,adm…

【Python笔记-设计模式】抽象工厂模式

一、说明 (一) 解决问题 抽象工厂是一种创建型设计模式&#xff0c;主要解决接口选择的问题。能够创建一系列相关的对象&#xff0c;而无需指定其具体类。 (二) 使用场景 系统中有多于一个的产品族&#xff0c;且这些产品族类的产品需实现同样的接口。 例如&#xff1a;有…

SQL注入的剩余类型

除了联合查询注入&#xff0c;报错注入&#xff0c;盲注注入 sql注入还有以下几类&#x1f9b9;&#x1f9b9;&#x1f9b9;&#x1f9b9;&#x1f9b9; 开始填坑 1.UA注入 原理&#xff1a;有些网站会把用户的UA信息写入数据库&#xff0c;用来收集和统计用户…

elementui的el-table自定义控制展开事件,实现“展开”“收起”的切换(两种效果)【超级完整式代码】

第一种&#xff1a;多行点击展开其他行不收起 先看效果图 直接上代码 【核心代码添加标注简单易懂】 <el-tableref"multipleTable":data"smsLogList.slice((currentPage - 1) * pageSize_, currentPage * pageSize_)"tooltip-effect"dark"st…

Python拼接字符串

在Python编程中&#xff0c;字符串拼接是一项常见的操作&#xff0c;它可以用于将多个字符串连接起来形成一个新的字符串&#xff0c;是处理文本数据和字符串操作的基本技巧之一。 1. 使用""运算符进行字符串拼接 最常见的字符串拼接方法是使用""运算符&…

专业130+总分390+第二名中国海洋大学946信号与系统考研经验电子信息通信

今年专业946信号与系统130&#xff0c;总分390&#xff0c;专业排名第2顺利上岸中国海洋大学&#xff0c;总结一下自己的复习经验希望对大家复习有所帮助&#xff0c;每个人的学习习惯不同&#xff0c;大家要对自己有信心&#xff0c;借鉴加上自己整合&#xff0c;属于自己的才…

在Windows上安装与配置Apache服务并结合内网穿透工具实现公网远程访问本地内网服务

文章目录 前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpolar web ui管理界面3.2 创建公网地址 4. 固定公网地址 前言 Apache作为全球使用较高的Web服务器…

Git 教程 | 将本地修改后的文件推送到 Github 指定远程分支上

Git 是一种分布式版本控制系统&#xff0c;用于敏捷高效地处理任何大小的项目。它是由 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的开源版本控制软件。Git 的本地克隆就是一个完整的版本控制存储库&#xff0c;无论脱机还是远程都能轻松工作。开发人员会在本地提交其工…