Redian新闻
>
关于多线程锁:锁代码还是锁资源?
avatar
关于多线程锁:锁代码还是锁资源?# Programming - 葵花宝典
p*y
1
有一个多线程的问题,我困惑了好久。多线程的mutex锁,是锁资源还是锁代码?
举个例子 我有100个文件存在磁盘上,分别命名为1.txt, 2.txt, 3.txt ...... 100.
txt.
现在我要创建多个线程,去往文件存东西。举例子如下(C++)。
mutex mx;
void write_to_file(string filename, string binary_data)
{
unique_lock lk(mx);
fstream f(filename);
f.write(&(binary_data[0]), binary_data.size());
f.close();
}
这段代码看似没有问题,但是却有个缺陷:锁的是代码,并非资源。换句话说,在多线
程下,任何
一个线程都会被另外一个线程block住,因为这里只要有两个线程同时碰到这个锁,就
会出现锁问题。
这时的多线程毫无意义了,因为这个函数其实无法并行。
可问题是,我往一个文件1.txt里面写东西,不应该影响另外一个线程往2.txt里面写东
西。
所以是不是应该锁资源,而不是锁代码?
如果是这样就应该这么写
//把文件名和mutex创建map,每个文件名都有一个独立的mutex
map mx_map;
void write_to_file(string filename, string binary_data)
{
unique_lock lk(mx_map[filename]);
fstream f(filename);
f.write(&(binary_data[0]), binary_data.size());
f.close();
}
这样,锁就是对应于某一个文件。多个线程的锁并不一定一致,也就不一定冲突。
请问诸位高人,我说的有道理么?
avatar
A*e
2
不存在锁代码,锁的都是资源

【在 p*****y 的大作中提到】
: 有一个多线程的问题,我困惑了好久。多线程的mutex锁,是锁资源还是锁代码?
: 举个例子 我有100个文件存在磁盘上,分别命名为1.txt, 2.txt, 3.txt ...... 100.
: txt.
: 现在我要创建多个线程,去往文件存东西。举例子如下(C++)。
: mutex mx;
: void write_to_file(string filename, string binary_data)
: {
: unique_lock lk(mx);
: fstream f(filename);
: f.write(&(binary_data[0]), binary_data.size());

avatar
p*y
3
上面的第一段代码,锁的是代码,因为任何一个线程到这里就会与其他线程冲突。
整个函数全部被锁住了。

【在 A*******e 的大作中提到】
: 不存在锁代码,锁的都是资源
avatar
A*e
4
想想你为何要加那个锁

【在 p*****y 的大作中提到】
: 上面的第一段代码,锁的是代码,因为任何一个线程到这里就会与其他线程冲突。
: 整个函数全部被锁住了。

avatar
c*e
5
看来c++的多线程,比java的简单多了。

【在 p*****y 的大作中提到】
: 有一个多线程的问题,我困惑了好久。多线程的mutex锁,是锁资源还是锁代码?
: 举个例子 我有100个文件存在磁盘上,分别命名为1.txt, 2.txt, 3.txt ...... 100.
: txt.
: 现在我要创建多个线程,去往文件存东西。举例子如下(C++)。
: mutex mx;
: void write_to_file(string filename, string binary_data)
: {
: unique_lock lk(mx);
: fstream f(filename);
: f.write(&(binary_data[0]), binary_data.size());

avatar
p*y
6
because another thread may write to the same file

【在 A*******e 的大作中提到】
: 想想你为何要加那个锁
avatar
c*e
7
i/o是最慢的地方,比如,数据库备份,一般也就一天一次。你这样频繁地写入文件,
会让系统变得很慢。

【在 p*****y 的大作中提到】
: because another thread may write to the same file
avatar
c*3
8
你这是画蛇添足,文件写操作,生成文件句柄的时候,操作系统可以加锁,其它人试图
打开文件写会失败。
avatar
c*e
9
right

【在 c****3 的大作中提到】
: 你这是画蛇添足,文件写操作,生成文件句柄的时候,操作系统可以加锁,其它人试图
: 打开文件写会失败。

avatar
d*a
10
是的。不同的进程,打开不同的文件,本可以不上锁的(看楼主说的应该是这样)。现
在楼主的写法,一个线程(共享内存的多线程)用write_to_file()打开文件1, 另一个
线程就不能用write_to_file()打开文件2了。

【在 c****3 的大作中提到】
: 你这是画蛇添足,文件写操作,生成文件句柄的时候,操作系统可以加锁,其它人试图
: 打开文件写会失败。

avatar
d*a
11
这样的话,一般有两个提高性能的方案:一是把这个文件拆解成小文件,二是用数据库
代替文件。两种做法都是为了提高I/O的并行度。

【在 p*****y 的大作中提到】
: because another thread may write to the same file
avatar
c*3
12
是啊,楼主不能埋头写程序,不管背景知识。
操作系统提供的资源。这些如果是竞争的,基本都有锁,你不用自己搞一个。
你只要使用这些资源和处理竞争资源失败的情况就行了。

【在 d***a 的大作中提到】
: 是的。不同的进程,打开不同的文件,本可以不上锁的(看楼主说的应该是这样)。现
: 在楼主的写法,一个线程(共享内存的多线程)用write_to_file()打开文件1, 另一个
: 线程就不能用write_to_file()打开文件2了。

avatar
h*c
13
锁就是双boolean,在 cpu 架构下确定atomic mutation.不存在什么资源锁,锁本身就
是一段代码。
avatar
w*g
14
depend on你的文件大小, 以及你是SSD还是HDD, 你这么写还真有可能是有
奇效. 如果你的binary_data很大, 有几G以上, 你的线程数很多, 而所有的
I/O都去同一个传统HDD, 那么这么写应该是效率最高的.
我经常写这种代码, 可以最大化磁盘吞吐量. mutex保护的是让磁头不要
乱动. 不过SSD的话就么写就没啥好处了. 这个和你问的没啥关系, 但是
事情的复杂性往往超出人的想象.

【在 p*****y 的大作中提到】
: 有一个多线程的问题,我困惑了好久。多线程的mutex锁,是锁资源还是锁代码?
: 举个例子 我有100个文件存在磁盘上,分别命名为1.txt, 2.txt, 3.txt ...... 100.
: txt.
: 现在我要创建多个线程,去往文件存东西。举例子如下(C++)。
: mutex mx;
: void write_to_file(string filename, string binary_data)
: {
: unique_lock lk(mx);
: fstream f(filename);
: f.write(&(binary_data[0]), binary_data.size());

avatar
d*a
15
楼主似乎修改了原文?
你这样写代码,相当于把1.txt到100.txt,合起来共用一个锁。一个线程访问1.txt,
另一个线程就不能访问任何一个其它的文件。
如果因为某种原因你要用mutex,那应该用100个mutex,每个文件给一个。

【在 p*****y 的大作中提到】
: 有一个多线程的问题,我困惑了好久。多线程的mutex锁,是锁资源还是锁代码?
: 举个例子 我有100个文件存在磁盘上,分别命名为1.txt, 2.txt, 3.txt ...... 100.
: txt.
: 现在我要创建多个线程,去往文件存东西。举例子如下(C++)。
: mutex mx;
: void write_to_file(string filename, string binary_data)
: {
: unique_lock lk(mx);
: fstream f(filename);
: f.write(&(binary_data[0]), binary_data.size());

avatar
p*y
16
其实我只是举一个例子,举的不好请原谅
我想说的,是unique_lock其实锁住的,是一段代码,而不是锁住一个资源
如果要锁住一个资源,就必须给这个资源一个独一无二的mutex

【在 p*****y 的大作中提到】
: 有一个多线程的问题,我困惑了好久。多线程的mutex锁,是锁资源还是锁代码?
: 举个例子 我有100个文件存在磁盘上,分别命名为1.txt, 2.txt, 3.txt ...... 100.
: txt.
: 现在我要创建多个线程,去往文件存东西。举例子如下(C++)。
: mutex mx;
: void write_to_file(string filename, string binary_data)
: {
: unique_lock lk(mx);
: fstream f(filename);
: f.write(&(binary_data[0]), binary_data.size());

avatar
p*y
17
万一不同的进程打开同一个文件呢?
所以我是给每一个文件上一个锁
我觉得这就是atomic的一个例子吧

【在 d***a 的大作中提到】
: 是的。不同的进程,打开不同的文件,本可以不上锁的(看楼主说的应该是这样)。现
: 在楼主的写法,一个线程(共享内存的多线程)用write_to_file()打开文件1, 另一个
: 线程就不能用write_to_file()打开文件2了。

avatar
l*s
18
锁的粒度问题,太细太粗都不好。
avatar
c*3
19
你这个问题的答案,还是和操纵系统有关。
线程(进程)最大的开销,就是线程(进程)切换,也就是一个线程,如果拿不到锁,
就会block,然后被操作系统切换走,这个上下文切换开销,如果线程多,就很高。有
的操纵系统是按照进程调度,有的是按照线程调度。
所以你的资源如果要锁,尽可能让程序能快速访问,减少block的几率。所以在锁里放
文件操纵或者类似运行速度慢的东西,是不明智的。除非没啥对性能的要求

【在 p*****y 的大作中提到】
: 其实我只是举一个例子,举的不好请原谅
: 我想说的,是unique_lock其实锁住的,是一段代码,而不是锁住一个资源
: 如果要锁住一个资源,就必须给这个资源一个独一无二的mutex

avatar
p*y
20
跑题了,你说的与线程毫无相关吧

【在 c*********e 的大作中提到】
: i/o是最慢的地方,比如,数据库备份,一般也就一天一次。你这样频繁地写入文件,
: 会让系统变得很慢。

avatar
p*y
21
多谢,这是我看到的唯一一个切题的答复!

【在 d***a 的大作中提到】
: 楼主似乎修改了原文?
: 你这样写代码,相当于把1.txt到100.txt,合起来共用一个锁。一个线程访问1.txt,
: 另一个线程就不能访问任何一个其它的文件。
: 如果因为某种原因你要用mutex,那应该用100个mutex,每个文件给一个。

avatar
d*a
22
不用客气。:) 改成用mutex array就好了。

【在 p*****y 的大作中提到】
: 多谢,这是我看到的唯一一个切题的答复!
avatar
c*3
23
原来你想知道的是这个,这是常识性问题。
当你创建一个新文件的时候,想想操作系统内部怎么锁文件的,每个文件一个锁。1万
个文件同时写,就有一万个锁

【在 p*****y 的大作中提到】
: 多谢,这是我看到的唯一一个切题的答复!
avatar
A*e
24
你自己概念混乱而已。代码和资源怎么混为一谈?再说一遍,你锁的是资源,锁代码是
个什么东西?锁资源是通过代码实现的。

【在 p*****y 的大作中提到】
: 多谢,这是我看到的唯一一个切题的答复!
avatar
p*y
25
多谢 其实一万个mutex有点类似于 atomic type

【在 c****3 的大作中提到】
: 原来你想知道的是这个,这是常识性问题。
: 当你创建一个新文件的时候,想想操作系统内部怎么锁文件的,每个文件一个锁。1万
: 个文件同时写,就有一万个锁

avatar
c*3
26
真实的内部不见得这么做,一个flag,用atomic操作也可以。但从外面看,就像锁一样。
从逻辑上也得这么做,别人不用这个资源,也被block,逻辑上说不过去
所以必然是只有竞争资源有锁,用的人被block,不相干的人没事。有好多资源,就有
好多锁。

【在 p*****y 的大作中提到】
: 多谢 其实一万个mutex有点类似于 atomic type
avatar
w*g
27
锁(mutex)都是锁资源. 楼主是同时锁了所有文件, 但还是锁资源.
和代码相关的是unique_lock. 但unique_lock其实不是锁, 而是
用RAII的方式对mutex加锁解锁. unique_lock在一个{} scope内
起作用.

【在 A*******e 的大作中提到】
: 你自己概念混乱而已。代码和资源怎么混为一谈?再说一遍,你锁的是资源,锁代码是
: 个什么东西?锁资源是通过代码实现的。

avatar
t*8
28
多线程的同步就是防止多线程操作下引起结果不确定
只要能避免结果不确定, 任何办法都是可以
不强调锁什么, 那是具体实现问题

【在 p*****y 的大作中提到】
: 有一个多线程的问题,我困惑了好久。多线程的mutex锁,是锁资源还是锁代码?
: 举个例子 我有100个文件存在磁盘上,分别命名为1.txt, 2.txt, 3.txt ...... 100.
: txt.
: 现在我要创建多个线程,去往文件存东西。举例子如下(C++)。
: mutex mx;
: void write_to_file(string filename, string binary_data)
: {
: unique_lock lk(mx);
: fstream f(filename);
: f.write(&(binary_data[0]), binary_data.size());

avatar
A*e
29
是这个道理

【在 w***g 的大作中提到】
: 锁(mutex)都是锁资源. 楼主是同时锁了所有文件, 但还是锁资源.
: 和代码相关的是unique_lock. 但unique_lock其实不是锁, 而是
: 用RAII的方式对mutex加锁解锁. unique_lock在一个{} scope内
: 起作用.

avatar
w*z
30
这说到点子上,既不是锁代码,也不是锁资源。

【在 t**8 的大作中提到】
: 多线程的同步就是防止多线程操作下引起结果不确定
: 只要能避免结果不确定, 任何办法都是可以
: 不强调锁什么, 那是具体实现问题

avatar
a9
31
这个写文件靠检测失败不现实,你总不能一直轮询吧

。现
一个

【在 c****3 的大作中提到】
: 是啊,楼主不能埋头写程序,不管背景知识。
: 操作系统提供的资源。这些如果是竞争的,基本都有锁,你不用自己搞一个。
: 你只要使用这些资源和处理竞争资源失败的情况就行了。

avatar
c*3
32
轮询其实也没什么,操作系统也有select(), epoll()之类的系统调用,更加有效率

【在 a9 的大作中提到】
: 这个写文件靠检测失败不现实,你总不能一直轮询吧
:
: 。现
: 一个

avatar
a9
33
先不说你这是自找麻烦,你解释一下更有效率从何而来。

【在 c****3 的大作中提到】
: 轮询其实也没什么,操作系统也有select(), epoll()之类的系统调用,更加有效率
avatar
c*3
34
你得先说为啥多线程要同时写一个文件,是多线程下载,还是什么其它应用。
没有实时性要求,当然可以轮询。
有实时性要求,要同时写一个文件,操作文件内部指针,用select,epoll的系统调用
,显然比用mutex去锁这个文件好

【在 a9 的大作中提到】
: 先不说你这是自找麻烦,你解释一下更有效率从何而来。
avatar
a9
35
用mutex锁文件又是咋锁的?

【在 c****3 的大作中提到】
: 你得先说为啥多线程要同时写一个文件,是多线程下载,还是什么其它应用。
: 没有实时性要求,当然可以轮询。
: 有实时性要求,要同时写一个文件,操作文件内部指针,用select,epoll的系统调用
: ,显然比用mutex去锁这个文件好

avatar
c*3
36
你没看一楼的问题,又不是真的锁文件,是对文件访问原子操作。

【在 a9 的大作中提到】
: 用mutex锁文件又是咋锁的?
avatar
l*i
37
general地讲,提高performance要尽量把一定不会冲突的partition用不同的锁
你这个case,如果不是hardlink或是symlink的话,肯定是完美的partition,锁资源的
方式既符合逻辑实现也不麻烦
鉴于你这个资源是文件,如果能保证相同文件在多线程中fd唯一的话,用flock应该比
用mutex容易实现一些

【在 p*****y 的大作中提到】
: 有一个多线程的问题,我困惑了好久。多线程的mutex锁,是锁资源还是锁代码?
: 举个例子 我有100个文件存在磁盘上,分别命名为1.txt, 2.txt, 3.txt ...... 100.
: txt.
: 现在我要创建多个线程,去往文件存东西。举例子如下(C++)。
: mutex mx;
: void write_to_file(string filename, string binary_data)
: {
: unique_lock lk(mx);
: fstream f(filename);
: f.write(&(binary_data[0]), binary_data.size());

avatar
p*y
38
多谢
我觉得所有文件共享一个锁是不合理的,因为这些文件互相独立
他们应该有各自的锁
但是这样的话,创建锁本身也是占用大量的资源

【在 l*****i 的大作中提到】
: general地讲,提高performance要尽量把一定不会冲突的partition用不同的锁
: 你这个case,如果不是hardlink或是symlink的话,肯定是完美的partition,锁资源的
: 方式既符合逻辑实现也不麻烦
: 鉴于你这个资源是文件,如果能保证相同文件在多线程中fd唯一的话,用flock应该比
: 用mutex容易实现一些

avatar
l*i
39
锁占的资源很少的,linux下的pthread_mutex实现应该就是几十个字节吧。当然和你的
应用有关,但是即使嵌入式应用,这个数量级的资源很可能也是可以忽略不计了。
自己斟酌~
avatar
T*x
40
这是对的。

【在 A*******e 的大作中提到】
: 不存在锁代码,锁的都是资源
avatar
l*i
41
perfbook
- Glossary and Bibliography
-- Code Locking
-- Data Locking

【在 A*******e 的大作中提到】
: 你自己概念混乱而已。代码和资源怎么混为一谈?再说一遍,你锁的是资源,锁代码是
: 个什么东西?锁资源是通过代码实现的。

avatar
h*c
42
data or code just a pointer
you have a double-boolean controll read/write associated to the pointer

【在 l*****i 的大作中提到】
: perfbook
: - Glossary and Bibliography
: -- Code Locking
: -- Data Locking

相关阅读
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。