博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
单例模式&线程安全
阅读量:6219 次
发布时间:2019-06-21

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

hot3.png

什么是线程安全?

1、程序通常为放在存储里面的物理文件;

2、进程(process):程序被触发后,执行者的权限与属性、程序的程序代码与所需数据等都会被加载到内存中,操作系统会给这个内存内的单元一个标识符(PID),子进程是父进程通过你过 fork-and-exec 流程复制出来的。

3、线程(thread):一个标准的线程由线程ID,当前指令指令(PC),寄存器集合和堆栈组成,在多线程OS中,线程是能独立运行的基本单位,因而也是独立调度和分派的基本单位。由于线程很“轻”,故线程的切换非常迅速且开销小(在同一进程中的)。

4、线程安全:在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

5、保证线程安全:

  1. 给共享的资源加把锁,保证每个资源变量每时每刻至多被一个线程占用。
  2. 让线程也拥有资源,不用去共享进程中的资源。如 使用threadlocal可以为每个线程的维护一个私有的本地变量.

c++11 静态成员线程安全吗?

C++0X以后,要求编译器保证内部静态变量的线程安全性,可以不加锁。但C++ 0X以前,仍需要加锁。C++0x是C++11标准成为正式标准之前的草案临时名字

实现一个线程安全且无内存泄漏的C++单例模式

单例:保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

特点:1.该类不能被复制;2.该类不能被公开的创造。

那么对于C++来说,它的构造函数,拷贝构造函数和赋值函数都不能被公开调用。

例如:程序的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取;一些全局初始化项

 懒汉模式:在第一次用到类实例的时候才会去实例化,

(1)静态指针 + 用到时初始化:  在单线程中,这样的写法是可以正确使用的,但是在多线程中就不行了,该方法是线程不安全的。

(2)静态 局部变量:该实现方式也是线程不安全的。如果存在多个单例对象的析构顺序有依赖时,可能会出现程序崩溃的危险。

#include 
template
class Singleton1{public: static T& GetInstance() { if (!m_instance){ m_instance = new T(); } return *m_instance; }private: Singleton1(); ~Singleton1(); static T* m_instance;};template
T* Singleton
::m_instance = NULL;class Singleton{public: //1.局部静态变量,并提供一个静态方法作为单例的接口,返回静态对象的引用, static Singleton & GetInstance() { static Singleton m_instance; return m_instance; } void print() { std::cout << "print test" << std::endl; }private: //让构造成为私有的,即该对象不能通过类外进行实例化。 //将其拷贝构造和赋值构造改为私有函数,不会发生对象拷贝。 Singleton() {}; Singleton(const Singleton&); Singleton& operator= (const Singleton&);};int main(){ Singleton::GetInstance()::print();}

饿汉模式:在单例类定义的时候就进行实例化。因为main函数执行之前,全局作用域的类成员静态变量m_Instance已经初始化,故没有多线程的问题。

        实现方式也有两种:(1)直接定义静态对象 (2)静态指针 + 类外初始化时new空间实现

#include 
//饿汉1:静态指针 + 类外初始化时new空间实现class Singleton1{ protected: Singleton1(){} private: static Singleton1* m_instance; public: static Singleton1* GetInstance(); void print(){ std::cout<<"Singleton1 print test"<
print(); Singleton& instance = Singleton::GetInstance(); instance.print();}

访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,以空间换时间。 

访问量较小时,采用懒汉实现。以时间换空间。

static 用法:

1、当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。

//a.cchar a = 'A'; // global variablevoid msg(){     printf("Hello\n");} //main.c int main(){     extern char a; // extern variable must be declared before use     printf("%c ", a);     (void)msg();     return 0;}

2、static保持变量内容的持久。(static变量中的记忆功能和全局生存期)

共有两种变量存储在静态存储区:全局变量和static变量,存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。PS:如果作为static局部变量在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。

3、static默认初始化为0(static变量)

其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00

C++中的类成员声明static

在类中声明static变量或者函数时,初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员

(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。      

(2)不能将静态成员函数定义为虚函数。      

(3)静态数据成员是静态存储的,所以必须对它进行初始化。 (程序员手动初始化,否则编译时一般不会报错,但是在Link时会报错误) 

(4)静态成员初始化在类体外:<数据类型><类名>::<静态数据成员名>=<值>

(5)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志。

 

 

 

 

转载于:https://my.oschina.net/u/347414/blog/1924620

你可能感兴趣的文章
C#未能加载类型
查看>>
SpringBoot自定义banner
查看>>
解决表格第一行colspan后 宽度失效问题
查看>>
#22 Eager Loading
查看>>
我的友情链接
查看>>
为iptables增加layer7补丁,实现应用层过滤
查看>>
MySQL聚合函数和GROUP BY子句
查看>>
问卷调查系统功能设计
查看>>
高项3月7日作业
查看>>
大型网站技术架构(一)大型网站架构演化
查看>>
Java基础学习总结(1)——equals方法
查看>>
如何定制或修改个性化登入界面?
查看>>
Java基础学习总结(4)——对象转型
查看>>
大型网站技术架构(六)网站的伸缩性架构
查看>>
直接来访问
查看>>
文件共享服务之vsftpd
查看>>
BZOJ1087[SCOI2005]互不侵犯——状压DP
查看>>
Java基础学习总结(3)——抽象类
查看>>
解决用eclipse打包三方库失败的方法
查看>>
浅谈linux性能调优之二:优化swap分区
查看>>