|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?FreeOZ用户注册
x
维基百科关于线程安全的定义:Thread safety is a computer programming concept applicable in the context of multi-threaded programs. A piece of code is thread-safe if it functions correctly during simultaneous execution by multiple threads.
一段代码(一般来说以一个函数为单位),如果是线程安全的,那么它必须能在多线程环境下始终保证能够"正确"执行。
关于可重入的定义:
一个函数可重入,意味着当这个函数正在运行的过程中,可以再次被运行。 显然,多线程并发就是这么一种情形。
那么,可重入和线程安全,是不是在说同一件事呢?毕竟他们的定义和描述的场景是如此的相像。如果不是的话,那是否很容易指出1,2个线程安全但是不可重入,或者可重入但是不线程安全的例子呢?
我们先来分析下线程安全的定义,最重要的是两点:
1. 多线程并发,也就是意味着,这段代码会在"同一时间"运行
2. 始终正确执行
那么什么情况下,一段代码在多线程情况下,会发生错误呢? 这个问题,其实很难回答,有很多时候,那些很有经验的老鸟,也会判断错误,不过,大体上,如果遇到以下情形,就可以怀疑这段代码在多线程环境下不安全:
from:wikipedia
以下情况意味着线程不安全:
以下情况线程安全:
- the only variables it uses are from the stack //只使用栈内存
- execution depends only on the arguments passed in, and //代码运行只依赖传入参数
- the only subroutines it calls have the same properties. //或者这段代码所调用的其它函数的运行结果只取决于传入参数
Such a sub-routine is sometimes called a "pure function", and is much like a mathematical function. //所谓函数式编程是也
以上对于集中线程不安全的情况,如果绕不开它们,又必须要求多线程安全,那么就得使用锁,线程局部存储等方式。 其他还有:
Mutual exclusion //使用锁对并发控制在访问临界资源时串行化Access to shared data is serialized using mechanisms that ensure only one thread reads or writes the shared data at any time. Great care is required if a piece of code accesses multiple shared pieces of data—problems include race conditions, deadlocks, livelocks, starvation, and various other ills enumerated in many operating systems textbooks.Thread-local storage //线程局部存储,绕开全局变量的一种方式Variables are localized so that each thread has its own private copy. These variables retain their values across subroutine and other code boundaries, and are thread-safe since they are local to each thread, even though the code which accesses them might be reentrant.Atomic operations //原子操作,一般而言对于i++这样的操作,都不是原子操作,所谓原子操作,是不可能被线程切换中断的操作。现代计算机的汇编指令,一般会有一些支持原子加减之类的操作Shared data are accessed by using atomic operations which cannot be interrupted by other threads. This usually requires using special machine language instructions, which might be available in a runtime library. Since the operations are atomic, the shared data are always kept in a valid state, no matter what other threads access it. Atomic operations form the basis of many thread locking mechanisms.
对于可重入:To be reentrant, a computer program or routine:- Must hold no static (or global) non-constant data. //无静态或全局变量
- Must not return the address to static (or global) non-constant data. //不能返回静态或全局变量的指针(只读的话没问题)
- Must work only on the data provided to it by the caller. //只能历来传入参数
- Must not rely on locks to singleton resources. //不能依靠锁或单例资源
- Must not modify its own code.[1] (unless executing in its own unique thread storage) //除了使用线程局部存储外,不能修改自身代码(数据) ,( 很多编程语言可以在运行时修改自身代码), C/C++也行,不过很tricky
- Must not call non-reentrant computer programs or routines. //不能调用非可重入的函数 (典型的递归定义计算机概念)
所以:
可重入与线程安全两个概念都关系到函数处理资源的方式。但是,他们有一定的区别。可重入概念会影响函数的外部接口,而线程安全只关心函数的实现。
- 大多数情况下,要将不可重入函数改为可重入的,需要修改函数接口,使得所有的数据都通过函数的调用者提供。
- 要将非线程安全的函数改为线程安全的,则只需要修改函数的实现部分。一般通过加入同步机制以保护共享的资源,使之不会被几个进程同时访问。
因此,相对线程安全来说,可重入性是更基本的特性,它可以保证线程安全:即,所有的可重入函数都是线程安全的,但并非所有的线程安全函数都是可重入的。
但是, 以上一般是对函数而言的,对C++的类而言,却反过来:
from:http://doc.qt.nokia.com/4.6/threads-reentrancy.html#reentrant
A thread-safe function can be called simultaneously from multiple threads, even when the invocations use shared data, because all references to the shared data are serialized.A reentrant function can also be called simultaneously from multiple threads, but only if each invocation uses its own data.
Hence, a thread-safe function is always reentrant, but a reentrant function is not always thread-safe.
C++ classes are often reentrant, simply because they only access their own member data. Any thread can call a member function on an instance of a reentrant class, as long as no other thread can call a member function on the same instance of the class at the same time.
例如,这是可重入的C++类:
- class Counter {public: Counter() { n = 0; } void increment() { ++n; } void decrement() { --n; } int value() const { return n; } private: int n; };
复制代码 这里的n, 如果变成静态或者全局变量,就不在是可重入的了。
如果需要thread-safe:
- class Counter{ public: Counter() { n = 0; } void increment() { QMutexLocker locker(&mutex); ++n; } void decrement() { QMutexLocker locker(&mutex); --n; } int value() const { QMutexLocker locker(&mutex); return n; } private: mutable QMutex mutex; int n; };
复制代码
|
|