求助关于变量的线程冲突安全问题

rbcic 2011-04-07 10:08:58
线程主函数如下代码:

int g_iValue = 0;
SetThreadProc()
{
g_iValue += 1000;
}


GetThreadProc()
{
printf("g_iValue");
}

对于SetThreadProc()只有一个线程调用,而GetThreadProc()会有很多个线程调用,
也就是只有一个线程写,其他线程都是读而已。
我想问的是对于g_iValue += 1000;这句代码是线程安全的么?是否有可能这句代码操作到一半的时候被GetThreadProc()
读取到数据,而导致g_iValue异常,
如果定义long long g_iValue呢?是否是线程安全的。

同样的,如果我在写线程里做memcpy操作的话,是否是线程安全?
...全文
120 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
JasonYak 2011-04-07
  • 打赏
  • 举报
回复
lz,为什么不在线程中直接读取系统时间呢!定时器不是太准确哦
qq120848369 2011-04-07
  • 打赏
  • 举报
回复
多线程,只要涉及到1个写操作,就要加锁了.

如果是纯读没写的话,就不需要锁了.

楼主代码得看读那一边怎么做处理,+=运算肯定会用寄存器做临时存储用于CPU运算的,其过程是内存数据存入寄存器,CPU根据寄存器内容运算后结果存于寄存器,之后再写回内存。

所以,读线程读数据是不会出错的,但是不是最新的数据就不一定了。但这种设计肯定是依赖读线程自己判断数据

的有效性,加锁与否看楼主自己了。
pengzhixi 2011-04-07
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 rbcic 的回复:]
引用 10 楼 pengzhixi 的回复:
读取的应该是一些规则的但是不一定是最新的值,不会出现你说的乱七八糟的值。不会出现说在写回内存的时候写一半字节的时候中断这个情况。


请问兄弟,那long long型也不会?对于char[]数组的memcpy操作也不会?
[/Quote]
额 ,就这里的情况讨论。如果你牵涉到数组那完全是另外一回事了。
rbcic 2011-04-07
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 pengzhixi 的回复:]
读取的应该是一些规则的但是不一定是最新的值,不会出现你说的乱七八糟的值。不会出现说在写回内存的时候写一半字节的时候中断这个情况。
[/Quote]

请问兄弟,那long long型也不会?对于char[]数组的memcpy操作也不会?
pengzhixi 2011-04-07
  • 打赏
  • 举报
回复
读取的应该是一些规则的但是不一定是最新的值,不会出现你说的乱七八糟的值。不会出现说在写回内存的时候写一半字节的时候中断这个情况。
direction917 2011-04-07
  • 打赏
  • 举报
回复
建议用个锁。就像操作系统原理那里边的似的。个人觉得不论读还是写,只要是并发,就要考虑共享数据的问题。
rbcic 2011-04-07
  • 打赏
  • 举报
回复
具体的说就是计数器线程本身每10ms递增10,其他很多个线程去读取这个计数值,就可以用来做时间判定了。
rbcic 2011-04-07
  • 打赏
  • 举报
回复
还有,我这个需求其实是放在个多线程共用的10ms计数器里用的,如果这都加锁的话,效率太低了。
rbcic 2011-04-07
  • 打赏
  • 举报
回复
其实我想问的只是对于g_iValue += 1000;
这单句代码而已。
在多线程读取的时候,是否他的值只可能是0,1000,2000,3000这样的规则结果,
是否可能因为单句代码中途未执行完毕的时候可能会被其他线程读取到非0,1000,2000,3000这样的既定结果规则数据。按我的理解整形是4个字节,g_iValue += 1000;操作是否可能在写入内存的某个中间字节的时候被其他线程读取到。

如果g_iValue是long long呢?是否更容易出上面我所说的问题
pengzhixi 2011-04-07
  • 打赏
  • 举报
回复
额 只是可能某些线程会读到修改前的数据。这个就看你这些读数据的线程的要求了。
delphiwcdj 2011-04-07
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 ouyh12345 的回复:]

不是线程安全,得加锁
[/Quote]
UP 临界区要加锁,否则读取的数据可能不正确
参考:

// MFC临界区类对象
CCriticalSection g_cs;
// 共享资源
char g_cArray[10];
UINT ThreadProc1(LPVOID pParam)
{
 // 进入临界区
 g_cs.Lock();
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[i] = ’a’;
  Sleep(1);
 }
 // 离开临界区
 g_cs.Unlock();
 return 0;
}
UINT ThreadProc2(LPVOID pParam)
{
 // 进入临界区
 g_cs.Lock();
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[10 - i - 1] = ’b’;
  Sleep(1);
 }
 // 离开临界区
 g_cs.Unlock();
 return 0;
}
void CSampleView::OnCriticalSectionMfc()
{
 // 启动线程
  AfxBeginThread(ThreadProc1, NULL);
 AfxBeginThread(ThreadProc2, NULL);
 // 等待计算完毕
 Sleep(300);
 // 报告计算结果
 CString sResult = CString(g_cArray);
 AfxMessageBox(sResult);
ouyh12345 2011-04-07
  • 打赏
  • 举报
回复
不是线程安全,得加锁
恨天低 2011-04-07
  • 打赏
  • 举报
回复
访问同一资源要用线程同步吧?
EnterCriticalSection(&m_CrtSec);
.
.
.
LeaveCriticalSection(&m_CrtSec);

额,你懂的!
justkk 2011-04-07
  • 打赏
  • 举报
回复
[Quote=引用楼主 rbcic 的回复:]
对于g_iValue += 1000;这句代码是线程安全的么?是否有可能这句代码操作到一半的时候被GetThreadProc()
读取到数据,而导致g_iValue异常,……
[/Quote]
存在这种可能,虽然存储的数据是对的,但是读取时可能是错的

可以考虑使用读写锁来保护
forster 2011-04-07
  • 打赏
  • 举报
回复
视 g_iValue += 1000;
的编译结构而定
32位程序可以一次性将值读到寄存器所以应该是安全的
小时了了 2011-04-07
  • 打赏
  • 举报
回复
只一个线程写入int型是安全的,因为只有一次写内存操作就可完成赋值,是原子操作。
long long是64位,至少要两次写内存才能完成,所以不安全会读到奇怪的值
pengzhixi 2011-04-07
  • 打赏
  • 举报
回复
long long 不安全。
rbcic 2011-04-07
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 qq120848369 的回复:]
多线程,只要涉及到1个写操作,就要加锁了.

如果是纯读没写的话,就不需要锁了.

楼主代码得看读那一边怎么做处理,+=运算肯定会用寄存器做临时存储用于CPU运算的,其过程是内存数据存入寄存器,CPU根据寄存器内容运算后结果存于寄存器,之后再写回内存。

所以,读线程读数据是不会出错的,但是不是最新的数据就不一定了。但这种设计肯定是依赖读线程自己判断数据

的有效性,加锁与否看楼主……
[/Quote]


是不是最新的数据没关系,只要数据不乱就行,对于这个寄存器的话,如果是long long型的数据,是否也是不会乱?
rbcic 2011-04-07
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 jasonyak 的回复:]
lz,为什么不在线程中直接读取系统时间呢!定时器不是太准确哦
[/Quote]

我在LINUX下开发的,如果多线程一直在调用gettimeofday函数的话,本身效率就低。所以我才另外开个计数器线程,用这个计数器做时间判定。这样效率会高。

64,653

社区成员

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

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