免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: Aquester
打印 上一主题 下一主题

[C] 一个线程对long类型变量进行修改,多个线程只读这个long类型值,需要加锁吗? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-12-17 19:57 |显示全部楼层 |倒序浏览
一个线程对long类型变量进行修改,多个线程只读这个long类型值,需要加锁吗?
比如,线程1:

long counter = 0;
void thread1()
{
    counter = time(NULL);
}

线程2:
void thread2()
{
   printf("%ld\n", counter);
}

上面对counter的修改和取值,需要加锁吗?32位和64平台是否有区别了?

[ 本帖最后由 Aquester 于 2008-12-17 22:27 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2008-12-17 22:17 |显示全部楼层

回复 #6 思一克 的帖子

如果不用锁,会有什么结果了?
对这个用锁,感觉开销太大。

论坛徽章:
0
3 [报告]
发表于 2008-12-17 22:21 |显示全部楼层
原帖由 calm_star 于 2008-12-17 21:17 发表
不需要吧,像 long这种简单类型的读写操作用不着加锁
如果要加的话这种情况考虑用读写锁


我记得以前测试过,在LINUX(x86)上没有出问题,但在HP-UX上会乱。
x86机有什么不同了?

论坛徽章:
0
4 [报告]
发表于 2008-12-17 22:30 |显示全部楼层
原帖由 思一克 于 2008-12-17 21:21 发表
需要加。++不是原子操作


如果将++counter修改成counter=time(NULL);了?

论坛徽章:
0
5 [报告]
发表于 2008-12-17 22:35 |显示全部楼层
If a double or long variable is not declared volatile, then for the purposes of load, store, read, and write operations it is treated as if it were two variables of 32 bits each; wherever the rules require one of these operations, two such operations are performed, one for each 32-bit half. The manner in which the 64 bits of a double or long variable are encoded into two 32-bit quantities and the order of the operations on the halves of the variables are not defined by The Java  Language Specification.

This matters only because a read or write of a double or long variable may be handled by an actual main memory as two 32-bit read or write operations that may be separated in time, with other operations coming between them. Consequently, if two threads concurrently assign distinct values to the same shared non-volatile double or long variable, a subsequent use of that variable may obtain a value that is not equal to either of the assigned values, but rather some implementation-dependent mixture of the two values.

An implementation is free to implement load, store, read, and write operations for double and long values as atomic 64-bit operations; in fact, this is strongly encouraged. The model divides them into 32-bit halves for the sake of currently popular microprocessors that fail to provide efficient atomic memory transactions on 64-bit quantities. It would have been simpler for the Java virtual machine to define all memory transactions on single variables as atomic; this more complex definition is a pragmatic concession to current hardware practice. In the future this concession may be eliminated. Meanwhile, programmers are cautioned to explicitly synchronize access to shared double and long variables.

“深入java虚拟机”提到int等不大于32位的类型上的操作都是原子操作

论坛徽章:
0
6 [报告]
发表于 2008-12-17 22:58 |显示全部楼层
C语言赋值语句不是原子操作
单单从硬件的角度来看赋值是非原子的,但是却忘记了应用程序是运行在内核之上的,很多的同步是由内核来完成的

在Linux Kernel Development(2nd)的进程管理一章中找到一下这句话.
On modern operating systems, processes provide two virtualizations: a virtualized processor and virtual memory. The virtual processor gives the process the illusion that it alone monopolizes the system, despite possibly sharing the processor among dozens of other processes. Chapter 4, "Process Scheduling," discusses this virtualization. Virtual memory lets the process allocate and manage memory as if it alone owned all the memory in the system. Virtual memory is covered in Chapter 11, "Memory Management." Interestingly, note that threads share the virtual memory abstraction while each receives its own virtualized processor.

对于应用程序来说,所有内存操作和寄存器操作都是在虚拟的(由内核来管理),也就是上面提到的虚拟内存和虚拟处理器.
对于多线程的程序来讲它们是共享虚拟内存,但是并不共享虚拟处理器(当然包括寄存器).
所以对多线程的程序原子操作只要关心内存操作是否为原子的,而并不需要关心寄存器.
因为Kernel在进行进程和线程调度的时候都会保护现场.

如果有不对之处请大家纠正,补充

论坛徽章:
0
7 [报告]
发表于 2008-12-18 21:55 |显示全部楼层
原帖由 hellioncu 于 2008-12-18 13:20 发表
应该是不需要的,读到的不是没改之前的,就是改之后的,对读来说加锁也是一样的结果


我想也是这样的,根据我以前的实际经验,在LINUX平台上测试没有发现问题,但在HP上确实存在问题,可以通过死循环,两个线程测试出来。另外,实在要加锁,也可以不使用mtext,而直接使用原子操作即可。

论坛徽章:
0
8 [报告]
发表于 2008-12-19 21:47 |显示全部楼层
谁有很权威的证明吗?
个人感觉确实不能光看CPU指令的个数。

论坛徽章:
0
9 [报告]
发表于 2008-12-21 09:40 |显示全部楼层
原帖由 drangon 于 2008-12-20 23:41 发表
可以不加锁,但需要使用原子操作,具体可以去看linux kernel的代码,简单来说x86上对long的读写是原子,但SMP下要加lock前缀锁总线,其他平台的可能有差异

感觉这个说得比较对

论坛徽章:
0
10 [报告]
发表于 2008-12-22 22:48 |显示全部楼层
原帖由 richardyang 于 2008-12-22 22:01 发表
long counter = 0;
void thread1()
{
    counter = time(NULL);
}

线程2:
void thread2()
{
   printf("%ld\n", counter);
}

对于这个问题的原义,其实都不需要线程1的,也不用同步,直接用:
...

这位兄弟说得不错,是直接可以
printf("%ld\n", time(NULL));
不过误会问题的意思了,问题只是举这样一个例子,实际需求是不能这样做的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP