请教个关于线程同步的问题

ShanTUT 2018-08-02 08:58:28
今天和领导在技术上有了点小争执。事情大概是这样的:
我在写代码时候,有一个16位的整型变量,被几个线程同时读写(注意:是既有读操作,也有些操作)。
代码的运行环境是windows环境下。
大概伪代码是这样的:

short i = 0; //要读写的16位整数

//读取16位整数的线程函数
void readThrFun()
{
while (true)
{
printf("%d\n", i); //读取并输出这个16位整数
}
}

//写16位整数的线程函数
void writeThrFun()
{
while(true)
{
++i; //对16位整数进行写操作(自增)
}
}


分歧在于是否需要在读写i的时候添加线程锁。
领导看我代码时候要求我加上,因为线程安全,也是公司的编码规范。
我认为不用。因为不管在windows32环境下,还是windows64环境下。
i的长度都小于一个机器字长。也就是说不管读i还是写i。
肯定都能在一个CPU时钟周期内完成的。不可能出现读写冲突的问题。
而且加一些无意义的线程锁,还会降低执行效率。
如果是各位大神,你们认为需要加这个线程锁么?
...全文
1198 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
yzhfirst1 2018-08-09
  • 打赏
  • 举报
回复
不是读写锁的问题?只要写其它线程不能访问,读可以有多个线程同时读。一个周期完成,如果是多核的呢
赵4老师 2018-08-07
  • 打赏
  • 举报
回复
《The Intel 64 and IA-32 Architectures Software Developer's Manual》
竞天问 2018-08-07
  • 打赏
  • 举报
回复
引用 32 楼 zhao4zhong1 的回复:
提醒:现代计算机的CPU十有八九都使用多核 、多级cache、指令流水线、……技术。
所以借助volatile想实现多线程锁的对应功能,基本上已经是痴人说梦了。

不是要实现多线程锁,也不考虑代码的可读/可维护性什么的,就单纯讨论这个知识点。
如果volatile要求编译器生成的指令就是直接操作内存单元,不管有什么底层优化技术,也得保证代码执行正确吧?
在非NUMA机器上(其实我不太懂NUMA),内存总线就一组吧,多线程对这个小于一个机器字的单元进行操作,会产生错误吗?
赵4老师 2018-08-07
  • 打赏
  • 举报
回复
提醒:现代计算机的CPU十有八九都使用多核 、多级cache、指令流水线、……技术。
所以借助volatile想实现多线程锁的对应功能,基本上已经是痴人说梦了。
竞天问 2018-08-07
  • 打赏
  • 举报
回复
不过如果程序运行在NUMA机器上……
竞天问 2018-08-07
  • 打赏
  • 举报
回复
引用 11 楼 zhao4zhong1 的回复:
[quote=引用 10 楼 DelphiGuy 的回复:]
读不用加,写要加,i最好定义为volatile short i = 0;

坊间传闻,volatile和多线程安全没关系。[/quote]


引用 12 楼 DelphiGuy 的回复:
[quote=引用 11 楼 zhao4zhong1 的回复:]
[quote=引用 10 楼 DelphiGuy 的回复:]
读不用加,写要加,i最好定义为volatile short i = 0;

坊间传闻,volatile和多线程安全没关系。[/quote]

volatile只是保证在读该数据的时候确实生成了一条读指令,而不是把之前读过的内容(如果两次读之间没有写过)或者写过的内容直接拿来用。
[/quote]
Quote from Window via C/C++:
First, let me point out one more thing: At the top of the previous code fragment, you'll notice the use of volatile. For this code fragment to even come close to working, the volatile type qualifier must be there. This tells the compiler that the variable can be modified by something outside of the application itself, such as the operating system, hardware, or a concurrently executing thread. Specifically, the volatile qualifier tells the compiler to exclude the variable from any optimizations and always reload the value from the variable's memory location.

像LZ这个需求,volatile是不是就够了?
qq_24438787 2018-08-05
  • 打赏
  • 举报
回复
有点小遗憾!!
youzhe_ren 2018-08-05
  • 打赏
  • 举报
回复
判断也需要周期,必须加锁!
yshuise 2018-08-04
  • 打赏
  • 举报
回复
你的领导是对的,要加锁。
啊大1号 2018-08-03
  • 打赏
  • 举报
回复
++i 其实涉及到序列点和副作用问题,C++2003将前缀++的结果从rvalue修改为lvalue,这导致了下列代码也是undefined behavior:
int i;
int j;
i = ++j;
当然这是另外一个话题了,具体可参考下:https://blog.csdn.net/a3192048/article/details/81079262
走好每一步 2018-08-03
  • 打赏
  • 举报
回复
自增操作要加的,自增操作是要用到寄存器的,如果还没运算完,就切换线程,那边读出来的值是不对的!

“i的长度都小于一个机器字长。也就是说不管读i还是写i。
肯定都能在一个CPU时钟周期内完成的。不可能出现读写冲突的问题”
这句话说明楼主没理解线程是怎么切换的
zhgwbzhd 2018-08-03
  • 打赏
  • 举报
回复
不仅仅是多线程考虑,很多地方都要考虑。
最最主要的是遇到多核CPU,没有保护区或者互斥或者锁,就出错了。
简单说,100个线程,每个线程增加10次,按道理来讲,应该得到1000次,但是多核下,没保护时,得到的值就不是1000.
  • 打赏
  • 举报
回复
自增是否一条指令取决于编译器的实现
一条指令也不代表是原子操作
ForestDB 2018-08-03
  • 打赏
  • 举报
回复
LZ只说了个场景(一个资源,两个线程一读一写),又没说业务需求(读写要不要同步),清官也难断啊。

如果不需要同步,你爱咋咋地。
如果需要同步,那么最简单的是用原子类型(atomic),不可用就用线程锁(mutex)。
其实同步还可以细分,比如允许多个线程同时读,那么可以使用读写锁;如果不允许多个线程同时读,例如更新的资源只能被消耗一次,那么就用互斥锁。
嘉兴老杨 2018-08-03
  • 打赏
  • 举报
回复
要加。
前面已经从技术角度进行了解释。
从编程规范,可读性以及后续维护来看,要加。否则后续别人维护代码容易出现问题。
以免我忘记 2018-08-03
  • 打赏
  • 举报
回复
要加,不然会出现内存错误,时间长了你就知道了。
赵4老师 2018-08-02
  • 打赏
  • 举报
回复
引用 10 楼 DelphiGuy 的回复:
读不用加,写要加,i最好定义为volatile short i = 0;

坊间传闻,volatile和多线程安全没关系。
  • 打赏
  • 举报
回复
读不用加,写要加,i最好定义为volatile short i = 0;


donjin9 2018-08-02
  • 打赏
  • 举报
回复
++自增操作好像不是一条指令吧。不是原子操作就要加锁了。可以把++改成原子函数。
eziowayne 2018-08-02
  • 打赏
  • 举报
回复
对于short变量多线程做自增操作是要加锁的。
加载更多回复(10)

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧