C++多线程笔记
- 最简单的创建线程(直接用一个函数为子线程入口)
//线程入口
void Mysthread()
{
cout << "线程开始" << endl;
cout << "线程结束" << endl;
}
int main()
{
//创建线程,一创建就相当于开启线程
thread my_thread(Mysthread);
//等待子线程my_thread运行完再继续运行
my_thread.join();
//my_thread.detach();//这个是不等待子线程运行和join不能一起用,且必须有一个。
}
- 用一个类来作为线程入口
class My_obj
{
public:
void operator()() //重载()
{
cout << "线程开始" << endl;
cout << "线程结束" << endl;
}
};
int main()
{
My_obj myobj;
thread my_thread(myobj); //会调用My_obj的拷贝函数,复制一份数据到子线程
my_thread.join();
}
- 带参数的子线程
void Mysthread(const int &i,char *ch,const string str)//用引用其实也是用了复制和主线程不是同一个数据(相当于值传递)
{ //指针就是用原来的数,真正的指针传递(用detach()的话就要注意)
cout << "线程开始" << endl;
cout << "线程结束" << endl;
}
int main()
{
int m = 1;
char mych[] = "this is a test!";
thread my_thread (Mysthread,m,mych,(string)mych);//避免隐式引用,特别是detach()
my_thread.join();
}
- 互斥锁(mutex)(lock和unlock要成对使用)
——每个共享数据都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该数据。 (有多个锁的话,锁上的顺序要一样,要不然会造成死锁)
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
//操作共享数据要锁上
my_mutex.lock();
msgRecvQueue.push_back(i);
//操作完要开锁
my_mutex.unlock();
}
}
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
//操作共享数据要锁上
my_mutex.lock();
if (!msgRecvQueue.empty())
{
int num = msgRecvQueue.front();
msgRecvQueue.pop_front();
}
//操作完要开锁
my_mutex.lock();
}
}
private:
//共享数据
list<int> msgRecvQueue;
//互斥锁
mutex my_mutex;
};
int main()
{
A myobj;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobj);
thread myInMsgObj(&A::inMsgRecvQueue, &myobj);
myInMsgObj.join();
myOutMsgObj.join();
}
- “智能的互斥锁”
——其是个类,在构造这个类时,调用构造函数会把参数的mutex给lock上,然后其析构函数里面就会调用unlock。 - std::lock_guard
std::lock_guard<std::mutex> my_guard(my_mutex);
std::lock_guard<std::mutex> my_guard(my_mutex,std::adopt_lock);//告诉其不用在构造函数中不用对my_mutex上锁
- std::unique_lock
std::unique_lock<std::mutex> my_unique_lock(my_mutex);
//告诉其不用在构造函数中不用对my_mutex上锁
std::unique_lock<std::mutex> my_unique_lock(my_mutex,std::adopt_lock);
//获取不到锁,会继续向下运行。可以用my_unique_lock.owns_lock来查看是否获取到锁。
std::unique_lock<std::mutex> my_unique_lock(my_mutex,std::try_to_lock);
//把my_mutex与my_unique_lock关联,其实也就是把my_mutex封装一层。
//其成员函数有lock,unlock(如果lock状态下,调用析构函数时也会自己unlock),
//try_lock,release(取消关联,如果取消关联后就要自己去把锁unlock)
std::unique_lock<std::mutex> my_unique_lock(my_mutex,std::try_to_lock);
获取当前线程的id:
std::this_thread::get_id()
使得子线程参数真正做到传递地址:
std::ref()函数
使得线程休眠:
std::chrono::milliseconds dura(1000);//1000毫秒=1秒
std::this_thread::sleep_for(dura);
移动语义(对象转移,不进行复制)
std::move()
在学习C++多线程的时候的一些不懂的东西的大杂烩:
- C++的会用到.和::和->的区别。
- A.B则A为对象或者结构体;
- A->B则A为指针,->是成员提取,A->B是提取A中的成员B,A只能是指向类、结构、联合的指针;
- A::B表示作用域A中的名称B,A可以是名字空间、类、结构;
- Lambda表达式
主要参考:https://www.cnblogs.com/DswCnblog/p/5629165.html
- []捕抓的变量在函数体里要改变要在后加上mutable 如:
int a = 111, b = 222;
auto func = [=, &b]()mutable {
a = 22; b = 333; cout << "a:" << a << " b:" << b <<endl;
};//输出的是a:22 b:333
func();
cout << "a:" << a << " b:" << b << endl;//输出的是a:111 b:333
- []想使得捕抓的变量在外部也改变要用引用捕抓,若是传值相当于只是复制了一份数据进函数体内使用,如上的代码,a就是不会改变外部的值,而b会改变外部的值。
- C++ const用法
主要参考:https://www.cnblogs.com/Forever-Kenlen-Ja/p/3776991.html
- const,修饰变量时表示其为常数,有define的效果,且会比define好(方便效率高),完整理由可参考:https://blog.csdn.net/weibo1230123/article/details/81981384
- 将函数传入参数声明为const,以指明使用这种参数仅仅是为了效率的原因,而不是想让调用函数能够修改对象的值。
-
要用引用的参数就要用const 。
-
sort包含在头文件algorithm中。