博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
什么代码才是线程安全的
阅读量:4165 次
发布时间:2019-05-26

本文共 2122 字,大约阅读时间需要 7 分钟。

对于多线程编程,很多人概念不清,写代码的时候要么是处处加锁,影响性能不说,还容易莫名其妙的死锁,还有人对多线程敬而远之。
所以学习多线程编程最重要的不是学习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
写好多线程安全的法宝就是封装,使数据有保护的被访问到
安全性:
局部变量>成员变量>全局变量

 

from:

 

转载:

其他文章:

你可能感兴趣的文章
Oracle中将毫秒数转换为timestamp类型的两种方法
查看>>
mybatis配置and rownum< minus 查询第几行到第几行数据的sql原型和mybatis原型。
查看>>
oracle的concat函数使用问题。
查看>>
eclipse编辑状态下怎样让指定行左移或右移?
查看>>
plsql developer如何导入导出表结构和数据以及如何复制表结构和数据?
查看>>
oracle如何去除某个字段中两边的空格?
查看>>
plsql developer如何在窗口列表直接可以修改表格中的数据?
查看>>
java自定义注解有什么作用?
查看>>
ORACLE中通过SQL语句(alter table)来增加、删除、修改字段
查看>>
js的Object对象如何访问中间有 . 点号的属性(键),获得其值?
查看>>
@ManyToOne和@OneToMany 注解
查看>>
Java集合(1) - List集合源码解析
查看>>
Java集合(2) - Map与AbstractMap源码解析
查看>>
Java集合(3) - HashMap源码解析与常见问题(一)
查看>>
Java集合(4) - HashMap-put()源码解析与常见问题(二)
查看>>
Java集合(5) - HashMap查删源码解析与常见问题(三)
查看>>
Java集合(6) - LinkedHashMap源码解析
查看>>
Java集合(7) - TreeMap源码解析
查看>>
Java集合(8) - Set与AbstractSet源码解析
查看>>
Java多线程(2) - 多线程之线程安全详解(synchronized、Lock)
查看>>