常问面试题---线程安全
对于多线程编程,很多人概念不清,写代码的时候要么是处处加锁,影响性能不说,还容易莫名其妙的死锁,还有人对多线程敬而远之。
所以学习多线程编程最重要的不是学习
API,
而是理解什么才是多线程安全的代码
从例子说起
#include <windows.h>
#include <process.h>
long
global1 = 0;
volatile
long
global2 = 0;
class
MyClass
{
public
:
MyClass() : m(0)
{
++m;
}
int
fun(
int
v)
{
return
m+v;
//-----------9
}
void
set
(
int
v)
{
m = v;
//-------------10
}
int
m;
};
MyClass global_object;
//-------------8
unsigned
int
__stdcall thread_fun1(
void
*param)
{
static
int
static2 = 0;
static
MyClass static_object;
//--------6
int
local1 = 0;
++local1;
//-------1
++static2;
//-------2
++global1;
//-------3
++global2;
//-------4
InterlockedIncrement(&global1);
//--------5
local1 = global_object.fun(local1);
//----------7
global_object.
set
(local1);
//---------------11
return
0;
}
unsigned
int
__stdcall thread_fun2(
void
*param)
{
++global1;
//-------3
++global2;
//-------4
InterlockedIncrement(&global1);
//--------5
global_object.
set
(1);
//-----------11
return
0;
}
int
main()
{
HANDLE thread1 = (HANDLE)_beginthreadex(0,0,&thread_fun1,0,0,0);
//thread 1
HANDLE thread2 = (HANDLE)_beginthreadex(0,0,&thread_fun1,0,0,0);
//thread 2
HANDLE thread3 = (HANDLE)_beginthreadex(0,0,&thread_fun2,0,0,0);
//thread 3
WaitForSingleObject(thread1,INFINITE);
WaitForSingleObject(thread2,INFINITE);
WaitForSingleObject(thread3,INFINITE);
return
0;
}
1.
局部变量局部使用是安全的
为什么
?
因为每个
thread
都有自己的运行堆栈,而局部变量是生存在堆栈中
,
大家不干扰。
所以代码
1
int local1;
++local1;
是安全的
2.
全局原生变量多线程读写是不安全的
全局变量是在堆
(heap)
中
long global1 = 0;
++global2;
++
这个操作其实分为两部,一个是读,另外一个是写
mov ecx,global
add ecx,1
mov global,ecx
所以代码
3
处是不安全的
3.
函数静态变量多线程读写也是不安全的
道理同
2
所以代码
2
处也是不安全的
4.volatile
能保证全局整形变量是多线程安全的么
不能。
volatile
仅仅是告诫
compiler
不要对这个变量作优化,每次都要从
memory
取数值,而不是从
register
所以代码
4
也不是安全
5.InterlockedIncrement
保证整型变量自增的原子性
所以代码
5
是安全的
6.function static object
的初始化是多线程安全的么
不是。
著名的
Meyer Singleton
其实不是线程安全的
Object & getInstance()
{
static Object o;
return o;
}
可能会造成多次初始化对象
所以代码
6
处是不安全的
7.
在
32
机器上,
4
字节整形一次
assign
是原子的
比如
i =10; //thread1
i=4; //thread2
不会导致
i
的值处于未知状态
,
要么是
10
要么是
4
写好多线程安全的法宝就是封装,使数据有保护的被访问到
安全性:
局部变量 > 成员变量 > 全局变量