C++11新特性
-
constexpr 指定在编译时求出值
-
mermaid
graph LR
源文件–cmakelist文件–>cmake
源文件–>makefile文件–>make
cmake–>makefile文件
make–>可执行文件
多线程并发
并发的基础概念
(1)并发,进程,线程
(2)多线程、多进程并发
(3)新标准库
类型
-
thread线程类
join()函数:阻塞主线程并等待子线程执行,deteach()函数:将子线程与主线程的关联分离。当主线结束时由运行时库负责清理
detach()同时也带来了一些问题,如子线程要访问主线中的对象,而主线中的对象又因为主线程结束而被销毁时,会导致程序崩溃。所以传递参数时需要注意一些陷阱。关于参数传递:
1、访问主线程对象以及指针问题
2、构造线程时隐式转换问题,子线程可以还来不及转换,主线程对象就销毁了,解决方法是构造线程时,构造一个临时对象传入。
joinable()线程是否可用
创建线程的几种方法:函数,对象类,应为线程创建时是浅拷贝
测试代码:
方法一
void my_test(const int &a,char *pmybuf){ cout<<a<<endl;//整形引用没有出现问题,在实际过程中会进行值传递 //使用指针必定出现问题 cout<<pmybuf<<endl; } } int main(){ int m_int=1; int my_int=&m_int; char mybuf[]="this is a test!"; thread mytobj(myprint,my_int,mybuf);//第一个是函数名,后两个是参数 mytobj.join(); //mytobj.detach(); return 0; }
传递临时变量时:不推荐使用引用类型,禁止使用指针类型
传递类变量
方法二
#include <iostream> #include <thread> #include <string> using namespace std; void myPrint(const int i, const string& pmybuf) { cout << i << endl; cout << pmybuf << endl; } int main() { int mvar = 1; int& mvary = mvar; char mybuf[] = "this is a test"; //如果detach了,这样仍然是不安全的 //因为存在主线程运行完了,mybuf被回收了,系统采用mybuf隐式类型转换成string //推荐先创建一个临时对象thread myThread(myPrint, mvar, string(mybuf));就绝对安全了。。。。 thread myThread(myPrint, mvar, mybuf); myThread.join(); //myThread.detach(); cout << "Hello World!" << endl; }
PS:C++ std::string 写时复制和深浅拷贝
// copy on write static void TestStringCopyCase1() { std::string a = "Hello World"; std::string b = a; printf("pointer of a: %p\n", a.c_str());//%p 转换为char类型并输出指针 printf("pointer of b: %p\n", b.c_str()); } // copy on write static void TestStringCopyCase2() { std::string a = "Hello World"; std::string b = a; printf("pointer of a: %p\n", a.c_str()); printf("pointer of b: %p\n", b.c_str()); b[0] = 'h'; // b += "!"; printf("pointer of a: %p\n", a.c_str()); printf("pointer of b: %p\n", b.c_str()); std::cout << a << std::endl; std::cout << b << std::endl; } // output: pointer of a: 0x1144028 pointer of b: 0x1144028 pointer of a: 0x1144028 pointer of b: 0x1144028 pointer of a: 0x1144028 pointer of b: 0x1144058//可以看出使用了string的写时复制 Hello World hello World
// misuse: modify b, but a is effected.
static void TestStringCopyCase3() {
std::string a = "Hello World";
std::string b = a;
char* char_array = (char *)b.c_str();
//绕过计数直接修改原始数据,即修改时如果引用计数不为一,那么就复制再修改
char_array[0] = 'h';
printf("pointer of a: %p\n", a.c_str());
printf("pointer of b: %p\n", b.c_str());
std::cout << a << std::endl;
std::cout << b << std::endl;
}
// output:
pointer of a: 0x1144028
pointer of b: 0x1144028
hello Wo
rld
hello World
//修改副本导致原件被修改
如何避免呢?
// deep copy to avoid misuse
static void TestStringCopyCase4() {
std::string a = "Hello World";
std::string b = a.c_str();
//deep copy
char* char_array = (char *)b.c_str();
char_array[0] = 'h';
printf("pointer of a: %p\n", a.c_str());
printf("pointer of b: %p\n", b.c_str());
std::cout << a << std::endl;
std::cout << b << std::endl;
}
// output:
pointer of a: 0x1144028
pointer of b: 0x1144058
Hello World
hello World
结论:如果使用std::string本身的成员函数或者操作符来操作std::string,它本身就是深拷贝的;
如果使用指针直接操作std::string源数据,会绕过“写时复制”机制,需要主动deep copy,以避免数据误写。
-
mutex互斥量类
包含4种类型:mutex类,recursive_mutex递归类,time_mutex定时类,recursive_timed_mutex定时递归类
死锁产生的条件:
-
资源是独占的且排他使用
-
进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺
-
进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源
-
循环等待条件
-
async,future创建后台任务并返回值
int mythread(){
std::chrono::milliseconds dura(5000);//
std::
}