p*****y 发帖数: 1049 | 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();
}
这样,锁就是对应于某一个文件。多个线程的锁并不一定一致,也就不一定冲突。
请问诸位高人,我说的有道理么? |
A*******e 发帖数: 2419 | 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());
|
p*****y 发帖数: 1049 | 3 上面的第一段代码,锁的是代码,因为任何一个线程到这里就会与其他线程冲突。
整个函数全部被锁住了。
【在 A*******e 的大作中提到】 : 不存在锁代码,锁的都是资源
|
A*******e 发帖数: 2419 | 4 想想你为何要加那个锁
【在 p*****y 的大作中提到】 : 上面的第一段代码,锁的是代码,因为任何一个线程到这里就会与其他线程冲突。 : 整个函数全部被锁住了。
|
c*********e 发帖数: 16335 | 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());
|
p*****y 发帖数: 1049 | 6 because another thread may write to the same file
【在 A*******e 的大作中提到】 : 想想你为何要加那个锁
|
c*********e 发帖数: 16335 | 7 i/o是最慢的地方,比如,数据库备份,一般也就一天一次。你这样频繁地写入文件,
会让系统变得很慢。
【在 p*****y 的大作中提到】 : because another thread may write to the same file
|
c****3 发帖数: 10787 | 8 你这是画蛇添足,文件写操作,生成文件句柄的时候,操作系统可以加锁,其它人试图
打开文件写会失败。 |
c*********e 发帖数: 16335 | 9 right
【在 c****3 的大作中提到】 : 你这是画蛇添足,文件写操作,生成文件句柄的时候,操作系统可以加锁,其它人试图 : 打开文件写会失败。
|
d***a 发帖数: 13752 | 10 是的。不同的进程,打开不同的文件,本可以不上锁的(看楼主说的应该是这样)。现
在楼主的写法,一个线程(共享内存的多线程)用write_to_file()打开文件1, 另一个
线程就不能用write_to_file()打开文件2了。
【在 c****3 的大作中提到】 : 你这是画蛇添足,文件写操作,生成文件句柄的时候,操作系统可以加锁,其它人试图 : 打开文件写会失败。
|
|
|
d***a 发帖数: 13752 | 11 这样的话,一般有两个提高性能的方案:一是把这个文件拆解成小文件,二是用数据库
代替文件。两种做法都是为了提高I/O的并行度。
【在 p*****y 的大作中提到】 : because another thread may write to the same file
|
c****3 发帖数: 10787 | 12 是啊,楼主不能埋头写程序,不管背景知识。
操作系统提供的资源。这些如果是竞争的,基本都有锁,你不用自己搞一个。
你只要使用这些资源和处理竞争资源失败的情况就行了。
【在 d***a 的大作中提到】 : 是的。不同的进程,打开不同的文件,本可以不上锁的(看楼主说的应该是这样)。现 : 在楼主的写法,一个线程(共享内存的多线程)用write_to_file()打开文件1, 另一个 : 线程就不能用write_to_file()打开文件2了。
|
h**********c 发帖数: 4120 | 13 锁就是双boolean,在 cpu 架构下确定atomic mutation.不存在什么资源锁,锁本身就
是一段代码。 |
w***g 发帖数: 5958 | 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());
|
d***a 发帖数: 13752 | 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());
|
p*****y 发帖数: 1049 | 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());
|
p*****y 发帖数: 1049 | 17 万一不同的进程打开同一个文件呢?
所以我是给每一个文件上一个锁
我觉得这就是atomic的一个例子吧
【在 d***a 的大作中提到】 : 是的。不同的进程,打开不同的文件,本可以不上锁的(看楼主说的应该是这样)。现 : 在楼主的写法,一个线程(共享内存的多线程)用write_to_file()打开文件1, 另一个 : 线程就不能用write_to_file()打开文件2了。
|
l*********s 发帖数: 5409 | |
c****3 发帖数: 10787 | 19 你这个问题的答案,还是和操纵系统有关。
线程(进程)最大的开销,就是线程(进程)切换,也就是一个线程,如果拿不到锁,
就会block,然后被操作系统切换走,这个上下文切换开销,如果线程多,就很高。有
的操纵系统是按照进程调度,有的是按照线程调度。
所以你的资源如果要锁,尽可能让程序能快速访问,减少block的几率。所以在锁里放
文件操纵或者类似运行速度慢的东西,是不明智的。除非没啥对性能的要求
【在 p*****y 的大作中提到】 : 其实我只是举一个例子,举的不好请原谅 : 我想说的,是unique_lock其实锁住的,是一段代码,而不是锁住一个资源 : 如果要锁住一个资源,就必须给这个资源一个独一无二的mutex
|
p*****y 发帖数: 1049 | 20 跑题了,你说的与线程毫无相关吧
【在 c*********e 的大作中提到】 : i/o是最慢的地方,比如,数据库备份,一般也就一天一次。你这样频繁地写入文件, : 会让系统变得很慢。
|
|
|
p*****y 发帖数: 1049 | 21 多谢,这是我看到的唯一一个切题的答复!
【在 d***a 的大作中提到】 : 楼主似乎修改了原文? : 你这样写代码,相当于把1.txt到100.txt,合起来共用一个锁。一个线程访问1.txt, : 另一个线程就不能访问任何一个其它的文件。 : 如果因为某种原因你要用mutex,那应该用100个mutex,每个文件给一个。
|
d***a 发帖数: 13752 | 22 不用客气。:) 改成用mutex array就好了。
【在 p*****y 的大作中提到】 : 多谢,这是我看到的唯一一个切题的答复!
|
c****3 发帖数: 10787 | 23 原来你想知道的是这个,这是常识性问题。
当你创建一个新文件的时候,想想操作系统内部怎么锁文件的,每个文件一个锁。1万
个文件同时写,就有一万个锁
【在 p*****y 的大作中提到】 : 多谢,这是我看到的唯一一个切题的答复!
|
A*******e 发帖数: 2419 | 24 你自己概念混乱而已。代码和资源怎么混为一谈?再说一遍,你锁的是资源,锁代码是
个什么东西?锁资源是通过代码实现的。
【在 p*****y 的大作中提到】 : 多谢,这是我看到的唯一一个切题的答复!
|
p*****y 发帖数: 1049 | 25 多谢 其实一万个mutex有点类似于 atomic type
【在 c****3 的大作中提到】 : 原来你想知道的是这个,这是常识性问题。 : 当你创建一个新文件的时候,想想操作系统内部怎么锁文件的,每个文件一个锁。1万 : 个文件同时写,就有一万个锁
|
c****3 发帖数: 10787 | 26 真实的内部不见得这么做,一个flag,用atomic操作也可以。但从外面看,就像锁一样。
从逻辑上也得这么做,别人不用这个资源,也被block,逻辑上说不过去
所以必然是只有竞争资源有锁,用的人被block,不相干的人没事。有好多资源,就有
好多锁。
【在 p*****y 的大作中提到】 : 多谢 其实一万个mutex有点类似于 atomic type
|
w***g 发帖数: 5958 | 27 锁(mutex)都是锁资源. 楼主是同时锁了所有文件, 但还是锁资源.
和代码相关的是unique_lock. 但unique_lock其实不是锁, 而是
用RAII的方式对mutex加锁解锁. unique_lock在一个{} scope内
起作用.
【在 A*******e 的大作中提到】 : 你自己概念混乱而已。代码和资源怎么混为一谈?再说一遍,你锁的是资源,锁代码是 : 个什么东西?锁资源是通过代码实现的。
|
t**8 发帖数: 4527 | 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());
|
A*******e 发帖数: 2419 | 29 是这个道理
【在 w***g 的大作中提到】 : 锁(mutex)都是锁资源. 楼主是同时锁了所有文件, 但还是锁资源. : 和代码相关的是unique_lock. 但unique_lock其实不是锁, 而是 : 用RAII的方式对mutex加锁解锁. unique_lock在一个{} scope内 : 起作用.
|
w**z 发帖数: 8232 | 30 这说到点子上,既不是锁代码,也不是锁资源。
【在 t**8 的大作中提到】 : 多线程的同步就是防止多线程操作下引起结果不确定 : 只要能避免结果不确定, 任何办法都是可以 : 不强调锁什么, 那是具体实现问题
|
|
|
a9 发帖数: 21638 | 31 这个写文件靠检测失败不现实,你总不能一直轮询吧
。现
一个
【在 c****3 的大作中提到】 : 是啊,楼主不能埋头写程序,不管背景知识。 : 操作系统提供的资源。这些如果是竞争的,基本都有锁,你不用自己搞一个。 : 你只要使用这些资源和处理竞争资源失败的情况就行了。
|
c****3 发帖数: 10787 | 32 轮询其实也没什么,操作系统也有select(), epoll()之类的系统调用,更加有效率
【在 a9 的大作中提到】 : 这个写文件靠检测失败不现实,你总不能一直轮询吧 : : 。现 : 一个
|
a9 发帖数: 21638 | 33 先不说你这是自找麻烦,你解释一下更有效率从何而来。
【在 c****3 的大作中提到】 : 轮询其实也没什么,操作系统也有select(), epoll()之类的系统调用,更加有效率
|
c****3 发帖数: 10787 | 34 你得先说为啥多线程要同时写一个文件,是多线程下载,还是什么其它应用。
没有实时性要求,当然可以轮询。
有实时性要求,要同时写一个文件,操作文件内部指针,用select,epoll的系统调用
,显然比用mutex去锁这个文件好
【在 a9 的大作中提到】 : 先不说你这是自找麻烦,你解释一下更有效率从何而来。
|
a9 发帖数: 21638 | 35 用mutex锁文件又是咋锁的?
【在 c****3 的大作中提到】 : 你得先说为啥多线程要同时写一个文件,是多线程下载,还是什么其它应用。 : 没有实时性要求,当然可以轮询。 : 有实时性要求,要同时写一个文件,操作文件内部指针,用select,epoll的系统调用 : ,显然比用mutex去锁这个文件好
|
c****3 发帖数: 10787 | 36 你没看一楼的问题,又不是真的锁文件,是对文件访问原子操作。
【在 a9 的大作中提到】 : 用mutex锁文件又是咋锁的?
|
l*****i 发帖数: 13 | 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());
|
p*****y 发帖数: 1049 | 38 多谢
我觉得所有文件共享一个锁是不合理的,因为这些文件互相独立
他们应该有各自的锁
但是这样的话,创建锁本身也是占用大量的资源
【在 l*****i 的大作中提到】 : general地讲,提高performance要尽量把一定不会冲突的partition用不同的锁 : 你这个case,如果不是hardlink或是symlink的话,肯定是完美的partition,锁资源的 : 方式既符合逻辑实现也不麻烦 : 鉴于你这个资源是文件,如果能保证相同文件在多线程中fd唯一的话,用flock应该比 : 用mutex容易实现一些
|
l*****i 发帖数: 13 | 39 锁占的资源很少的,linux下的pthread_mutex实现应该就是几十个字节吧。当然和你的
应用有关,但是即使嵌入式应用,这个数量级的资源很可能也是可以忽略不计了。
自己斟酌~ |
T*******x 发帖数: 8565 | 40 这是对的。
【在 A*******e 的大作中提到】 : 不存在锁代码,锁的都是资源
|
|
|
l*****i 发帖数: 13 | 41 perfbook
- Glossary and Bibliography
-- Code Locking
-- Data Locking
【在 A*******e 的大作中提到】 : 你自己概念混乱而已。代码和资源怎么混为一谈?再说一遍,你锁的是资源,锁代码是 : 个什么东西?锁资源是通过代码实现的。
|
h**********c 发帖数: 4120 | 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
|