C/C++多线程编程/并发--学习记录-锁(1)-创新互联
多线程/并发核心需要解决的问题就是数据的互斥和同步
在陆河等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都做网站、网站建设 网站设计制作按需开发,公司网站建设,企业网站建设,品牌网站设计,营销型网站,外贸网站建设,陆河网站建设费用合理。
对于多线程处理数据时(通常是共享内存机制实现), 为了避免多个线程同时访问同一个资源, 我们需要添加锁(lock)
来实现共享资源互斥访问.
Mutex
)/自旋锁(Spin Lock
)- 互斥锁(
Mutex
)/自旋锁(Spin Lock
)的区别.
C++ 中的线程锁
- 互斥锁是sleep-waiting, 自旋锁是busy-waiting
- 假设我们有一个两个处理器core1和core2计算机,现在在这台计算机上运行的程序中有两个线程:T1和T2分别在处理器core1和core2上运行,两个线程之间共享着一个资源。
首先我们说明互斥锁的工作原理,互斥锁是是一种sleep-waiting的锁。假设线程T1获取互斥锁并且正在core1上运行时,此时线程T2也想要获取互斥锁(pthread_mutex_lock),但是由于T1正在使用互斥锁使得T2被阻塞。当T2处于阻塞状态时,T2被放入到等待队列中去,处理器core2会去处理其他任务而不必一直等待(忙等)。也就是说处理器不会因为线程阻塞而空闲着,它去处理其他事务去了。
而自旋锁就不同了,自旋锁是一种busy-waiting的锁。也就是说,如果T1正在使用自旋锁,而T2也去申请这个自旋锁,此时T2肯定得不到这个自旋锁。与互斥锁相反的是,此时运行T2的处理器core2会一直不断地循环检查锁是否可用(自旋锁请求),直到获取到这个自旋锁为止。
从“自旋锁”的名字也可以看出来,如果一个线程想要获取一个被使用的自旋锁,那么它会一致占用CPU请求这个自旋锁使得CPU不能去做其他的事情,直到获取这个锁为止,这就是“自旋”的含义。
当发生阻塞时,互斥锁可以让CPU去处理其他的任务;而自旋锁让CPU一直不断循环请求获取这个锁。通过两个含义的对比可以我们知道“自旋锁”是比较耗费CPU的。
1. 使用C++11中提供了
std::mutex
, 对于多线程加锁操作提供了很好的支持. [mutex: 互斥量]
std::mutex
. [不推荐]直接使用
mutex
的lock
和unlock
. 不推荐, 未及时释放锁就会导致死锁, 容易造成死锁现象
#include#include#include#include#include#includeint counter = 0;
std::mutex mtx; // 保护counter
void increase(int time) {for (int i = 0; i< time; i++) {mtx.lock();
// 当前线程休眠1毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1));
counter++;
mtx.unlock();
}
}
int main(int argc, char** argv) {std::thread t1(increase, 10000);
std::thread t2(increase, 10000);
t1.join();
t2.join();
std::cout<< "counter:"<< counter<< std::endl;
return 0;
}
- 对于std::mutex对象,任意时刻最多允许一个线程对其进行上锁
- mtx.lock():调用该函数的线程尝试加锁。如果上锁不成功,即:其它线程已经上锁且未释放,则当前线程block。如果上锁成功,则执行后面的操作,操作完成后要调用mtx.unlock()释放锁,否则会导致死锁的产生
- mtx.unlock():释放锁
- std::mutex还有一个操作:mtx.try_lock(),字面意思就是:“尝试上锁”,与mtx.lock()的不同点在于:如果上锁不成功,当前线程不阻塞。
std::lock_guard
推荐
std::lock_guard
只有构造函数和析构函数。简单的来说:当调用构造函数时,会自动调用传入的对象的lock()
函数,而当调用析构函数时,自动调用unlock()
函数(这就是所谓的RAII)。- RAII是Resource Acquisition Is Initialization(wiki上面翻译成 “资源获取就是初始化”)的简称,是C++语言的一种管理资源、避免泄漏的惯用法。利用的就是C++构造的对象最终会被销毁的原则。
#include#include#include#include#include#includeint counter = 0;
std::mutex mtx; // 保护counter
void increase_proxy(int time, int id) {for (int i = 0; i< time; i++) {// std::lock_guard对象构造时,自动调用mtx.lock()进行上锁
// std::lock_guard对象析构时,自动调用mtx.unlock()释放锁
std::lock_guardlk(mtx);
// 线程1上锁成功后,抛出异常:未释放锁
if (id == 1) {throw std::runtime_error("throw excption....");
}
// 当前线程休眠1毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1));
counter++;
}
}
void increase(int time, int id) {try {increase_proxy(time, id);
}
catch (const std::exception& e){std::cout<< "id:"<< id<< ", "<< e.what()<< std::endl;
}
}
int main(int argc, char** argv) {std::thread t1(increase, 10000, 1);
std::thread t2(increase, 10000, 2);
t1.join();
t2.join();
std::cout<< "counter:"<< counter<< std::endl;
return 0;
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
文章题目:C/C++多线程编程/并发--学习记录-锁(1)-创新互联
链接地址:http://ybzwz.com/article/jogji.html