1.线程不锁,导致最终获取数据不对
int sum = 0;
mutex mu;
void A()
{
for (int i=0;i<100000;++i)
{
sum++;
}
cout << "a is :" << sum << endl;
}
int main()
{
thread a(A);
thread b(A);
thread c(A);
a.join();
b.join();
c.join();
cout << "父线程" << endl;
cout << "a is :" << sum << endl;
return 0;
}
2.线程加mutex锁,方法:对数据采用lock()和unlock()方法成对出现
void A()
{
for (int i=0;i<100000;++i)
{
mu.lock();
sum++;
mu.unlock();
}
cout << "a is :" << sum << endl;
}
3.lock()和unlock(),有两个问题:
1.写两个太麻烦
2.如果在lock过程抛出异常会导致死锁
采用的方法是用lock_guard<mutex>,它会自己解锁。在某个lock_guard对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而lock_guard的生命周期结束之后,它所管理的锁对象会被解锁。
void A()
{
for (int i=0;i<100000;++i)
{
lock_guard<mutex> lockmu(mu);
sum++;
}
cout << "a is :" << sum << endl;
}
4.当有两个锁锁数据的时候,如果调用顺序不同会产生死锁,在A中顺序是a,b,在B中顺序是b,a
会导致程序死锁。
int sum = 0;
mutex mu;
mutex mu2;
void A()
{
for (int i=0;i<100000;++i)
{
lock_guard<mutex> lockmu(mu);
sum++;
lock_guard<mutex> lockmu2(mu2);
sum++;
}
cout << "a is :" << sum << endl;
}
void B()
{
for (int i = 0; i < 100000; ++i)
{
lock_guard<mutex> lockmu2(mu2);
sum++;
lock_guard<mutex> lockmu(mu);
sum++;
}
cout << "a is :" << sum << endl;
}
int main()
{
thread a(A);
thread b(B);
a.join();
b.join();
cout << "父线程" << endl;
cout << "a is :" << sum << endl;
return 0;
}
5.解决的办法是采用lock开始就规定好锁的顺序,并在每个锁中加入adopt_lock适配lock的参数,可以保证锁的顺序。
int sum = 0;
mutex mu;
mutex mu2;
void A()
{
for (int i=0;i<100000;++i)
{
lock(mu, mu2);
lock_guard<mutex> lockmu(mu,adopt_lock);
sum++;
lock_guard<mutex> lockmu2(mu2, adopt_lock);
sum++;
}
cout << "a is :" << sum << endl;
}
void B()
{
for (int i = 0; i < 100000; ++i)
{
lock(mu, mu2);
lock_guard<mutex> lockmu2(mu2, adopt_lock);
sum++;
lock_guard<mutex> lockmu(mu, adopt_lock);
sum++;
}
cout << "a is :" << sum << endl;
}
int main()
{
thread a(A);
thread b(B);
a.join();
b.join();
cout << "父线程" << endl;
cout << "a is :" << sum << endl;
return 0;
}
6.和lock_guard相对的还有一个更灵活的锁unique_lock,
unique_lock优点:
1.在lock_guard的范围下,所有代码都被锁住,而unique_lock范围下,如果不加参数(defer_lock),效果如下:
2.unique_lock可以通过move函数转移控制权,而lock_guard不行。
unique_lock缺点:
消耗更多性能。
7.多线程的call_once的使用
转载:C++11中的std::call_once_爱很遥远-CSDN博客
8.条件变量condition_variable使用
主要要点:在于相当于在全局设置了一个记录器,被触发一次,就会记录一次,然后要用的时候就减一次。
转载:C++-----------notify_one()与notify_all()_1.01的博客-CSDN博客
condition_variable cv;
mutex mu;
vector<int> sum;
void A()
{
for (int i = 0; i < 10; ++i)
{
unique_lock<mutex> locker(mu);
cv.notify_one();
sum.emplace_back(i);
cout << "sum is:" << i << endl;
}
}
void B()
{
int data = 0;
while (data!=9)
{
unique_lock<mutex> locker(mu);
cv.wait(locker, []() {return sum.size()!=0; });
data = sum[0];
sum.erase(sum.begin());
cout << "data is:" << data << endl;
}
}
int main()
{
thread a(A);
thread b(B);
a.join();
b.join();
cout << "父线程" << endl;
return 0;
}
9.异步线程future和 async、promise
1.std::promise 是C++11并发编程中常用的一个类,常配合std::future使用。
在两个线程中,promise p,future f=p.get_future, 两个线程同时启动,当遇到f.get(),如果另一个线程不给p设置值,f就会一直阻塞,等待,线程p中被设置了值,才继续下去
多线程笔记一 future和async的使用_qq_1410888563的博客-CSDN博客
void A(promise<int> &p)
{
cout << "1:" << endl;
p.set_value(10);
cout << "3:" << endl;
int a = 20;
a = a * 10;
cout << "data is:" <<a << endl;
}
void B(future<int>& f)
{
cout << "2:" << endl;
int data =f.get();
cout << "data is:" << data <<endl;
}
int main()
{
promise<int> pro;
future<int> fu = pro.get_future();
thread a(A,ref(pro));
thread b(B,ref(fu));
a.join();
b.join();
cout << "父线程" << endl;
return 0;
}
10.packaged-task
主要作用:使代码更加简洁
int A(int a, int& b)
{
b += 10;
return a + b;
}
int main()
{
packaged_task<int(int, int&)> t(A);
future<int> f = t.get_future();
int num = 10;
thread a(move(t),10, ref(num));
a.join();
int b= f.get();
cout << "b is :" <<b<< endl;
cout << "num is :" << num << endl;
return 0;
}
11.时间限制4种类型方法
int main()
{
thread t(A);
this_thread::sleep_for(chrono::milliseconds(3));
chrono::steady_clock::time_point tp = chrono::steady_clock::now() + chrono::microseconds(4);
this_thread::sleep_until(tp);
mutex mu;
unique_lock<mutex> locker(mu);
locker.try_lock_for(chrono::microseconds(3));
locker.try_lock_until(tp);
condition_variable cond;
cond.wait_for(locker,chrono::microseconds(3));
cond.wait_until(locker, tp);
promise<int> p;
future<int> f = p.get_future();
f.wait_for(chrono::microseconds(3));
f.wait_until(tp);
return 0;
}