- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章C++11各种锁的具体使用由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
这样比喻:单位上有一台打印机(共享数据a),你要用打印机(线程1要操作数据a),同事老王也要用打印机(线程2也要操作数据a),但是打印机同一时间只能给一个人用,此时,规定不管是谁,在用打印机之前都要向领导申请许可证(lock),用完后再向领导归还许可证(unlock),许可证总共只有一个,没有许可证的人就等着在用打印机的同事用完后才能申请许可证(阻塞,线程1lock互斥量后其他线程就无法lock,只能等线程1unlock后,其他线程才能lock)。那么,打印机就是共享数据,访问打印机的这段代码就是临界区,这个必须互斥使用的许可证就是互斥量(锁).
互斥量是为了解决数据共享过程中可能存在的访问冲突的问题。这里的互斥量保证了使用打印机这一过程不被打断.
死锁 。
多线程编程时要考虑多个线程同时访问共享资源所造成的问题,因此可以通过加锁解锁来保证同一时刻只有一个线程能访问共享资源;使用锁的时候要注意,不能出现死锁的状况; 。
死锁就是多个线程争夺共享资源导致每个线程都不能取得自己所需的全部资源,从而程序无法向下执行.
产生死锁的四个必要条件(面试考点):
互斥(资源同一时刻只能被一个进程使用)请求并保持(进程在请资源时,不释放自己已经占有的资源)不剥夺(进程已经获得的资源,在进程使用完前,不能强制剥夺)循环等待(进程间形成环状的资源循环等待关系) 互斥量mutex 。
互斥量mutex就是互斥锁,加锁的资源支持互斥访问 。
直接操作 mutex,即直接调用 mutex 的 lock / unlock 函数 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
std::mutex g_mutex;
int
g_count = 0;
void
Counter() {
g_mutex.lock();
int
i = ++g_count;
std::cout <<
"count: "
<< i << std::endl;
// 前面代码如有异常,unlock 就调不到了。
g_mutex.unlock();
}
int
main() {
const
std::
size_t
SIZE = 4;
// 创建一组线程。
std::vector<std::
thread
> v;
v.reserve(SIZE);
for
(std::
size_t
i = 0; i < SIZE; ++i) {
v.emplace_back(&Counter);
}
// 等待所有线程结束。
for
(std::
thread
& t : v) {
t.join();
}
return
0;
}
|
lock_guard 。
使用 lock_guard 自动加锁、解锁。原理是 RAII,和智能指针类似.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
std::mutex g_mutex;
int
g_count = 0;
void
Counter() {
// lock_guard 在构造函数里加锁,在析构函数里解锁。
std::lock_guard<std::mutex> lock(g_mutex);
int
i = ++g_count;
std::cout <<
"count: "
<< i << std::endl;
}
int
main() {
const
std::
size_t
SIZE = 4;
std::vector<std::
thread
> v;
v.reserve(SIZE);
for
(std::
size_t
i = 0; i < SIZE; ++i) {
v.emplace_back(&Counter);
}
for
(std::
thread
& t : v) {
t.join();
}
return
0;
}
|
unique_lock 。
使用 unique_lock 自动加锁、解锁。 unique_lock 与 lock_guard 原理相同,但是提供了更多功能(比如可以结合条件变量使用)。 注意:mutex::scoped_lock 其实就是 unique_lock 的 typedef.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
std::mutex g_mutex;
int
g_count = 0;
void
Counter() {
std::unique_lock<std::mutex> lock(g_mutex);
int
i = ++g_count;
std::cout <<
"count: "
<< i << std::endl;
}
int
main() {
const
std::
size_t
SIZE = 4;
std::vector<std::
thread
> v;
v.reserve(SIZE);
for
(std::
size_t
i = 0; i < SIZE; ++i) {
v.emplace_back(&Counter);
}
for
(std::
thread
& t : v) {
t.join();
}
return
0;
}
|
std::recursive_mutex 。
就像互斥锁(mutex)一样,递归互斥锁(recursive_mutex)是可锁定的对象,但它允许同一线程获得对互斥锁对象的多级所有权(多次lock).
这允许从已经锁定它的线程锁定(或尝试锁定)互斥对象,从而获得对互斥对象的新所有权级别:互斥对象实际上将保持对该线程的锁定,直到调用其成员 unlock 的次数与此所有权级别的次数相同.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include <iostream>
#include <thread>
#include <mutex>
std::recursive_mutex mtx;
void
print_block (
int
n,
char
c) {
mtx.lock();
mtx.lock();
mtx.lock();
for
(
int
i=0; i<n; ++i) { std::cout << c; }
std::cout <<
'\n'
;
mtx.unlock();
mtx.unlock();
mtx.unlock();
}
int
main ()
{
std::
thread
th1 (print_block,50,
'*'
);
std::
thread
th2 (print_block,50,
'$'
);
th1.join();
th2.join();
return
0;
}
|
std::timed_mutex 。
定时互斥锁是一个可时间锁定的对象,旨在通知何时关键代码需要独占访问,就像常规互斥锁一样,但还支持定时尝试锁定请求.
。
lock | 调用线程将锁定timed_mutex,并在必要时进行阻塞(其行为与 mutex 完全相同) |
try_lock | 尝试锁定 timed_mutex,而不进行阻塞(其行为与互斥锁完全相同) |
try_lock_for | 尝试锁定 timed_mutex, 最多阻塞 rel_time 时间 |
try_lock_until | 尝试锁定 timed_mutex,最多阻塞到 abs_time 时间点 |
unlock | 解锁 timed_mutex,释放对其的所有权(其行为与 mutex 相同) |
。
std::recursive_timed_mutex 。
递归定时互斥锁将 recursive_timed 和 timed_mutex 的功能结合到一个类中:它既支持通过单个线程获 取多个锁定级别又支持定时的 try_lock 请求.
成员函数与 timed_mutex 相同.
once_flag、call_once使用 。
在多线程中,有一种场景是某个任务只需要执行一次,可以用C++11中的std::call_once函数配合std::once_flag来实现。多个线程同时调用某个函数,std::call_once可以保证多个线程对该函数只调用一次 。
实现线程安全的单例模式 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
//h文件
#pragma once
#include <thread>
#include <iostream>
#include <mutex>
#include <memory>
class
Task
{
private
:
Task();
public
:
static
Task* task;
static
Task* getInstance();
void
fun();
};
//cpp文件
Task* Task::task;
Task::Task()
{
std::cout <<
"构造函数"
<< std::endl;
}
Task* Task::getInstance()
{
static
std::once_flag flag;
std::call_once(flag, []
{
task =
new
Task();
});
return
task;
}
void
Task::fun()
{
std::cout <<
"hello world!"
<< std::endl;
}
|
需要#include<condition_variable>,该头文件中包含了条件变量相关的类,其中包括std::condition_variable类 。
如何使用?std::condition_variable类搭配std::mutex类来使用,std::condition_variable对象(std::condition_variable cond;)的作用不是用来管理互斥量的,它的作用是用来同步线程,它的用法相当于编程中常见的flag标志(A、B两个人约定flag=true为行动号角,默认flag为false,A不断的检查flag的值,只要B将flag修改为true,A就开始行动).
类比到std::condition_variable,A、B两个人约定notify_one为行动号角,A就等着(调用wait(),阻塞),只要B一调用notify_one,A就开始行动(不再阻塞).
std::condition_variable的具体使用代码实例可以参见文章中“生产者与消费者问题”章节.
wait(locker)
wait函数需要传入一个std::mutex(一般会传入std::unique_lock对象),即上述的locker。wait函数会自动调用 locker.unlock() 释放锁(因为需要释放锁,所以要传入mutex)并阻塞当前线程,本线程释放锁使得其他的线程得以继续竞争锁。一旦当前线程获得notify(通常是另外某个线程调用 notify_* 唤醒了当前线程),wait() 函数此时再自动调用 locker.lock()上锁.
cond.notify_one(): 随机唤醒一个等待的线程 。
cond.notify_all(): 唤醒所有等待的线程 。
std::condition_variable::wait 有两个重载:
1
2
3
4
|
void
wait( std::unique_lock<std::mutex>& lock ); (1) (since C++11)
template
<
class
Predicate >
void
wait( std::unique_lock<std::mutex>& lock, Predicate pred ); (2) (since C++11)
|
void wait( std::unique_lockstd::mutex& lock ) 。
先unlock之前获得的mutex,然后阻塞当前的执行线程。把当前线程添加到等待线程列表中,该线程会持续 block 直到被 notify_all() 或 notify_one() 唤醒。被唤醒后,该thread会重新获取mutex,获取到mutex后执行后面的动作.
线程block时候也可能被意外或者错误唤醒.
template< class Predicate > void wait( std::unique_lockstd::mutex& lock, Predicate pred ),
该重载设置了第二个参数 Predicate, 只有当pred为false时,wait才会阻塞当前线程。盖崇仔等同于下面:
该情况下,线程被唤醒后,先重新判断pred的值。如果pred为false,则会释放mutex并重新阻塞在wait。因此,该mutex必须有pred的权限。该重载消除了意外唤醒的影响.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <condition_variable>
#include <deque>
#include <chrono>
std::deque<
int
> q;
std::mutex mu;
std::condition_variable condi;
void
function_1()
{
int
count = 10;
while
(count > 0)
{
std::unique_lock<std::mutex> locker(mu);
q.push_back(count);
locker.unlock();
condi.notify_one();
//通知一个等待线程激活 condi.notify_all()激活所有线程
count--;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void
function_2()
{
int
data = 100;
while
(data > 1)
{
std::unique_lock<std::mutex> locker(mu);
condi.wait(locker,
//解锁locker,并进入休眠 收到notify时又重新加锁
[]() {
return
!q.empty(); });
//如果q不为空 线程才会被激活
data = q.front();
q.pop_front();
locker.unlock();
std::cout << data << std::endl;
}
}
int
main()
{
std::
thread
t1(function_1);
std::
thread
t2(function_2);
t1.join();
t2.join();
return
0;
}
|
std::shared_mutex 是读写锁,提供两种访问权限的控制:共享性(shared)和排他性(exclusive)。通过lock/try_lock获取排他性访问权限,通过lock_shared/try_lock_shared获取共享性访问权限。这样的设置对于区分不同线程的读写操作特别有用。shared_mutex是c++17中引入的,使用时需要注意编译器版本.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#include <iostream>
#include <mutex> // For std::unique_lock
#include <shared_mutex>
#include <thread>
class
ThreadSafeCounter {
public
:
ThreadSafeCounter() =
default
;
// Multiple threads/readers can read the counter's value at the same time.
unsigned
int
get()
const
{
std::shared_lock lock(mutex_);
return
value_;
}
// Only one thread/writer can increment/write the counter's value.
void
increment() {
std::unique_lock lock(mutex_);
value_++;
}
// Only one thread/writer can reset/write the counter's value.
void
reset() {
std::unique_lock lock(mutex_);
value_ = 0;
}
private
:
mutable
std::shared_mutex mutex_;
unsigned
int
value_ = 0;
};
int
main() {
ThreadSafeCounter counter;
auto increment_and_print = [&counter]() {
for
(
int
i = 0; i < 3; i++) {
counter.increment();
std::cout << std::this_thread::get_id() <<
' '
<< counter.get() <<
'\n'
;
// Note: Writing to std::cout actually needs to be synchronized as well
// by another std::mutex. This has been omitted to keep the example small.
}
};
std::
thread
thread1(increment_and_print);
std::
thread
thread2(increment_and_print);
thread1.join();
thread2.join();
}
|
所谓原子操作,就是多线程程序中“最小的且不可并行化的”操作。对于在多个线程间共享的一个资源而言,这意味着同一时刻,多个线程中有且仅有一个线程在对这个资源进行操作,即互斥访问。提到“互斥”访问,熟悉多线程开发的同学可能立即想到Windows平台下使用的临界区/CRITICAL_SECTION、互斥体/Mutex。实现互斥通常需要平台相关的特殊指令,在C++11标准之前,这意味着需要在C/C++代码中嵌入平台相关的内联汇编代码。 平台相关意味着:1.你必须了解平台相关的编译器扩展;2.无法跨平台运行你的多线程程序.
多线程中需要同步的总是资源/数据,而不是代码。因此C++11对数据进行了更为良好的抽象,引入"原子数据类型"/atomic类型,以达到对开发者掩盖互斥锁、临界区的目的。要知道,这些临界区、互斥锁才是平台相关的东西。来看下面的示例代码.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include<atomic>
#include<thread>
#include<iostream>
using
namespace
std;
std::atomic_llong total{ 0 };
//原子数据类型
void
func(
int
)
{
for
(
long
long
i = 0; i<100000000LL; ++i)
{
total += i;
}
}
int
main()
{
thread
t1(func, 0);
thread
t2(func, 0);
t1.join();
t2.join();
cout<<total<<endl;
//9999999900000000
return
0;
}
|
原子数据类型/atomic类型 。
atomic模板类 。
1
2
3
4
5
6
7
8
9
10
11
12
|
template
<
class
T>
struct
atomic
//example
#include<atomic>
void
test()
{
std::atomic_int nThreadData;
// std::atomic_int <----> std::atomic<int>
nThreadData = 10;
nThreadData.store(10);
//TODO: use nThreadData here;
}
|
对于内置型数据类型,C11和C++11标准中都已经提供了实例化原子类型,如下表所示:
atomic类型原子操作接口如下 。
到此这篇关于C++11各种锁的具体使用的文章就介绍到这了,更多相关C++11各种锁内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/ly1390811049/article/details/119515282 。
最后此篇关于C++11各种锁的具体使用的文章就讲到这里了,如果你想了解更多关于C++11各种锁的具体使用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!