可重入和线程安全简单介绍

可重入和线程安全

可重入和线程安全这两个术语,经常出现在计算机编程中,用于指明类和函数在多线程程序中的使用。

可重入:若一个程序或子程序可以“安全的被并行执行(Parallel computing)”,则称其为可重入(reentrant或re-entrant)的。

若一个函数是可重入的,则该函数:

1、不能含有静态(全局)非常量数据。

2、不能返回静态(全局)非常量数据的地址。

3、只能处理由调用者提供的数据。

4、不能依赖于单实例模式资源的锁。

5、不能调用(call)不可重入的函数。

线程安全:指某个函数、 函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成。

线程安全的方法可以被多个线程同时调用,即使这些调用都使用到了共享的数据,因为它对共享数据的使用都是序列化,也就是每个序列操作全部完成之前是不可能被别的线程的使用而中断的。可重入的方法也能被多个线程同时调用,但是必须是每个调用都只使用自己的数据。因此,线程安全的方法必定是可重入的,但是可重入的方法未必是线程安全的。

一个类是可重入的,指的是,只要每个线程用的是不同的类的实例。一个类是线程安全的,指的是它的成员方法可以安全的被多个线程同时调用,即使每个线程使用的是相同的类实例。

C++类一般情况下都是可重入的,因为类的成员方法一般都只能操作成员数据,每个线程都是通过自己的类实例调用成员方法,不可能存在别的线程调用同一个类实例的方法。

以下这个类就不是可重入的,很明显,存在静态数据成员。

class Counter

{

public:

Counter() { }

static  void increment() { ++n; }

static  void decrement() { --n; }

static  int value() { return n; }

private:

static  int n;

};

class Counter

{

public:

Counter() { }

void increment() { ++n; }

void decrement() { --n; }

int value() { return n; }

private:

int n;

};

简单的改一下,把static去掉就可以成为一个可重入的类。但是它并不是线程安全的,当存在多个线程试图修改n的时候,结果就有可能是未定义的。因为++  和—操作并不是原子性的操作,其包括以下步骤:

1、  把变量加载到一个寄存器。

2、  寄存器进行自增或自减。

3、  把寄存器的值重新保存到变量中。

假设存在两个线程A和B同时保存了n的旧的的值到寄存器中,再各自进行自增,随后再写回变量,这样便会出现覆盖,n实际也只增加了1。上面说过,就是线程安全方法对数据的操作必须是一序列的不可中断的,就如上面的这个例子,线程A在执行步骤1,2,3必须是连续操作的,在完成3个步骤之前,线程B不允许操作n。因此我们一般情况下必须用互斥变量对数据操作进行加锁。如下

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    int n;

};

QMutexLocker 对 n 加锁和解锁,保证了对n的操作是序列化的。我们知道const成员方法不能改变实例的任何数据,所以mutex必须的声明为mutable,因为在value() const进行加锁和解锁改变了mutex。

Qt的许多类都是可重入的,但比不上线程安全的,因为保证线程安全要在每个方法的重复的进行加锁和解锁,那是相当麻烦的。

可重入与线程安全两个概念都关系到函数处理资源的方式。可重入概念会影响函数的外部接口,而线程安全只关心函数的实现。

大多数情况下,要将不可重入函数改为可重入的,需要修改函数接口,使得所有的数据都通过函数的调用者提供。

要将非线程安全的函数改为线程安全的,则只需要修改函数的实现部分。一般通过加入同步机制以保护共享的资源,使之不会被几个线程同时访问。

http://blog.csdn.net/hai200501019/article/details/8496989

时间: 2024-10-11 05:04:10

可重入和线程安全简单介绍的相关文章

可重入与线程安全(大多数Qt类是可重入,非线程安全的)

可重入与线程安全 在Qt文档中,术语“可重入”与“线程安全”被用来说明一个函数如何用于多线程程序.假如一个类的任何函数在此类的多个不同的实例上,可以被多个线程同时调用,那么这个类被称为是“可重入”的.假如不同的线程作用在同一个实例上仍可以正常工作,那么称之为“线程安全”的. 大多数c++类天生就是可重入的,因为它们典型地仅仅引用成员数据.任何线程可以在类的一个实例上调用这样的成员函数,只要没有别的线程在同一个实例上调用这个成员函数.举例来讲,下面的Counter 类是可重入的: class Co

Writing Reentrant and Thread-Safe Code(译:编写可重入和线程安全的代码)

Writing Reentrant and Thread-Safe Code 编写可重入和线程安全的代码 (http://www.ualberta.ca/dept/chemeng/AIX-43/share/man/info/C/a_doc_lib/aixprggd/genprogc/writing_reentrant_thread_safe_code.htm) In single-threaded processes there is only one flow of control. The

可重入和线程安全

线程安全这个词对我来说已经不是很陌生的了,但是遇到一个叫做可重入函数的词,它给我的感觉和线程安全是这么的相近,但既然拿出来了,肯定是有区别的,下面就说说他们之间的区别和联系. 要先解释这两个词语才行. 线程安全:似乎是在牛客网刷题的时候看到一个正确的选项说的是,线程安全问题都是由全局变量及静态变量引起的. 可重入函数:按我现在的理解就是,因为不同的执行流执行同一个函数,导致函数的执行顺序和预期的函数执行顺序不同导致执行逻辑不正确,得不到正确的结果 这么一看,可重入函数和线程安全似乎没有什么大的关

可重入与线程安全

看了好多文章,觉得这俩概念很容易混淆.在这里先总结一下自己的理解. 维基百科对可重入的定义是:  若一个程序或子程序可以"安全的被并行执行(Parallel computing)",则称其为可重入(reentrant或re-entrant)的. 可重入的概念是在单线程操作系统的时代提出的.可重入会影响函数的外部接口,而线程安全只关心函数的实现. 可重入函数未必是线程安全的,线程安全的函数也未必是可重入的.例如: 例1: 一个函数打开某个文件并读入数据.这个函数是可重入的,因为它的多个实

两种方式实现自己的可重入锁

本篇文章将介绍两种自己动手实现可重入锁的方法. 我们都知道JDK中提供了一个类ReentrantLock,利用这个类我们可以实现一个可重入锁,这种锁相对于synchronized来说是一种轻量级锁. 重入锁的概念 重入锁实际上指的就是一个线程在没有释放锁的情况下,可以多次进入加锁的代码块. public void a() { lock2.lock(); System.out.println("a"); b(); lock2.unlock(); } public void b() { l

linux可重入、异步信号安全和线程安全

一 可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断.它首先执行该信号处理程序中的指令.如果从信号处理程序返回(例如没有调用exit或longjmp),则继续执行在捕获到信号时进程正在执行的正常指令序列(这和当一个硬件中断发生是所发生的事情相似.)但是在信号处理器里,我们并不知道当信号被捕获时进程正在执行哪里的代码. 如果进程正使用malloc在它的堆上分配额外的内存,而此时由于捕捉到信号而插入执行该信号处理程序,其中又调用了malloc,这会

可重入函数、线程安全、volatile

一. POSIX 中对可重入和线程安全这两个概念的定义: Reentrant Function:A function whose effect, when called by two or more threads,is guaranteed to be as if the threads each executed the function one after another in an undefined order, even if the actual execution is inte

ReentrantLock(重入锁)简单源码分析

1.ReentrantLock是基于AQS实现的一种重入锁. 2.先介绍下公平锁/非公平锁 公平锁 公平锁是指多个线程按照申请锁的顺序来获取锁. 非公平锁 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁.有可能,会造成优先级反转或者饥饿现象. 3.重入锁/不可重入锁 可重入锁:广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁. 不可重入锁

线程安全和可重入函数

一.线程安全 1.线程安全函数:C语言中局部变量是在栈中分配的,任何未使用静态数据或其他共享资源的函数都是线程安全的. (1)对于同一进程的不同线程来说,每个线程的局部变量都是私有的,而全局变量.局部静态变量.分配于堆的变量都是共享的,即是非线程安全的. (2) 在对这些共享变量进行访 问时,如果要保证线程安全,则必须通过加锁的方式. 2.线程安全的:                   如果一个函数在同一时刻可以被多个线程安全地调用,就称该函数是线程安全的.