C++11: Multi-Thread思考.

本文深入探讨了多线程环境下数据并发访问可能导致的问题,包括未同步化数据访问、写至半的数据和重新安排的语句,并详细解释了这些问题如何影响程序的预期行为。文章还提出了原子性和顺序性作为解决这些问题的关键性质,并通过实例展示了如何避免多线程编程中的常见陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用多线程几乎总是伴随着"数据的并发访问",多个线程之间毫无干系的并行运行是很罕见的。线程有可能提供数据给其他线程处理,或者是备妥必要条件(比如shared state)用以供其它线程使用,或者是供其它线程ublock.

首先我们要明确的是自C++11起:不同的对象拥有各自的内存区.

Concurrent Data Access为什么会造成问题?

1,Unsynchronized data access(未同步化的数据访问):并行运行的两个线程读写同一个内存中的数据,不知道哪个语句先来.

2,Haft-written data(写至半的数据):某个线程正在读该内存中的数据,另一个线程则尝试改动它。

3,Reordered statement(重新安排的语句):语句和操作由于编译器的优化被重新安排执行的次序,甚至不自行,也许对于一个单线程的程序是没有问题的,但是对于多线程的组合却破坏了预期的行为.

Unasynchronized Data Access:

if(val >=0 ){
  //间隙1
  f(val);
}else{
  //间隙2
  f(-val);
}

在单线程的环境中上述代码是没有任何问题的,但是在多线程的环境中,如果多个线程处理val的值,也就是说val的值在间隙1和间隙2处被改变!!!!!!这样不就超出我们的预期了么.

std::vector<int> v;
....
if(!v.empty()){
  //间隙.
  std::cout<< v.front() << std::endl;
}

在单线程的环境中上述的代码也是没问题的,但是在多线程的环境中很有可能在间隙处v变成empty.

Half-Written Data(写至半途而废的数据):

考虑我们有一个变量:

long long x = 0;

某个线程对它写入数值:

x = -1;

另外一个线程读取它:

std::cout << x;

程序的输出是什么?也就是说当另外一个线程读取它的时候可能是:

1, 0(x的旧值)-如果第一个线程尚未赋予她-1;

2,-1(x的新值) -如果第一线程已经赋予了它-1;

3,任何其他值-如果在第一个线程对x赋予-1的过程中.

不仅仅是上面我们所举例的long long类型、即使基本数据类型如int和bool,标准也不保证读写是atomic(不可切割的,意思是独占的不可被打断的,也就是说读的时候是一定不能被写的)。

Reordered Statement(重新安排的语句):

假设有两个共享对象,一个是long类型用来将data从某个线程传递到另一个线程,另外一个是bool readyFlag,用来表示第一个线程是否已经提供了数据.

long data;
bool readyFlag = false;

一般都会想到,将“某线程中对data的设定”和“另外一个线程中队data的销毁”同步化(synchronize),于是写出下面的代码.

//线程1

data = 42;
readyFlag = ture;
//线程2

while(!readyFlag){
   ;
}

foo(data);

在不知道任何细节的情况下,几乎一开始都会认为线程2的foo()函数肯定是在data有值42之后才会被调用的。认为对foo()的调用只有在readyFlag为ture的前提下才能触及,而为ture又发生在42赋值给data之后,因为赋值之后才令readyFlag为ture.

但是事实并非如此编译器优化过后可能重新安排语句:

readyFlag = ture;
data = 42;

 

解决以上问题所需要的性质:

Atomicity(不可切割性):这意味着读写一个变量其行为都是独占的,排他的,无任何打断的,因此一个线程不可能读到“因另外一个线程而造成的”中间状态.

Order(次序):我们需要一些方法保证“某些具体指定语句”的次序.

 

转载于:https://my.oschina.net/SHIHUAMarryMe/blog/677289

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值