static变量初始化顺序
1.1 全局变量、文件域的static变量和类的static成员变量在main函数执行之前初始化
1.2 局部静态变量在第一次被使用时初始化
static变量的线程安全
2.1 非局部静态变量是线程安全的
2.2 局部静态变量在C++11后也是线程安全的
分为懒汉式和饿汉式,在使用前全局对象已经创建的是饿汉式单例,在使用的时候创建的是懒汉式单例
01. 普通懒汉式单例,线程不安全
// 懒汉式单例模式,线程不安全
class SingleInstance {
public:
static SingleInstance *GetInstance() {
if (m_SingleInstance == nullptr)
m_SingleInstance = new SingleInstance;
return m_SingleInstance;
private:
SingleInstance();
~SingleInstance();
SingleInstance(const SingleInstance &signal) = delete;
SingleInstance &operator=(const SingleInstance &signal) = delete;
private:
static SingleInstance *m_SingleInstance;
SingleInstance *SingleInstance::m_SingleInstance = NULL;
02. 加锁的懒汉式单例,线程安全
//懒汉式单例,加锁,线程安全
class SingleInstance {
public:
static SingleInstance *GetInstance() {
pthread_mutex_lock(&mutex);
if (m_SingleInstance == nullptr)
m_SingleInstance = new SingleInstance;
return m_SingleInstance;
pthread_mutex_unlock(&mutex);
private:
SingleInstance();
~SingleInstance();
SingleInstance(const SingleInstance &signal) = delete;
SingleInstance &operator=(const SingleInstance &signal) = delete;
static SingleInstance *m_SingleInstance;
static pthread_mutex_t mutex;
SingleInstance *SingleInstance::m_SingleInstance = NULL;
03. 局部静态变量实现的懒汉式单例,C++11后线程安全(推荐使用的方式)
// 局部静态变量实现的懒汉式单例,C++11后线程安全
class SingleInstance {
public:
static SingleInstance *GetInstance() {
static SingleInstance instance;
return &instance;
private:
SingleInstance();
~SingleInstance();
SingleInstance(const SingleInstance &signal) = delete;
SingleInstance &operator=(const SingleInstance &signal) = delete;
04. 饿汉式单例,天生线程安全,因为在main函数前已经初始化
//饿汉式单例,天生线程安全
class SingleInstance {
public:
static SingleInstance *GetInstance() { return m_SingleInstance; }
private:
SingleInstance();
~SingleInstance();
SingleInstance(const SingleInstance &signal) = delete;
SingleInstance &operator=(const SingleInstance &signal) = delete;
private:
static SingleInstance *m_SingleInstance;
SingleInstance *SingleInstance::m_SingleInstance = new SingleInstance;
static变量初始化顺序1.1 全局变量、文件域的static变量和类的static成员变量在main函数执行之前初始化1.2 局部静态变量在第一次被使用时初始化static变量的线程安全2.1 非局部静态变量是线程安全的2.2 局部静态变量在C++11后也是线程安全的单例模式分为懒汉式和饿汉式,在使用前全局对象已经创建的是饿汉式单例,在使用的时候创建的是懒汉式单例01. 普通懒汉式单例,线程不安全// 懒汉式单例模式,线程不安全class SingleInstance
static 是一种修饰符,它被用来控制变量的存储方式和可见性。
2、什么时候用static?
(1).需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。
(2).有些时候,我们希望我们所引用的类,只存在一个对象,这时候,我们就可以通过static来实现一个单例类。这种模式也叫单例模式。
被static修饰...
线程安全的单例模式
一、懒汉模式:即第一次调用该类实例的时候才产生一个新的该类实例,并在以后仅返回此实例。
需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety。
使用double-check来保证thread safety。但是如果处理大量数据时,该锁才成为严重的性能瓶颈。
1、静态成员实例的懒汉模式:
class Singleton
private:
static Singleton* m_instance;
Singleton(){}
public:
static Singleton* getInst
静态变量(static)的线程安全
C++11 Singleton. Static variable is thread safe? Why? stack overflow
在单例模式中我们常常会遇到如下的方法,但是假如同时有多个线程调用了这个函数,它能保证线程安全吗?
Singleton& Singleton::GetInstance()
static Singleton i...
std::cout << “construct start” << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5)); //构造函数中休眠5s
num++;
std::cout <
C++实现一个线程安全的单例工厂实现代码
我们见到经常有人用 static 局部对象的方式实现了类似单例模式,最近发现一篇文章明确写明 编译器在处理 static局部变量的时候 并不是线程安全的 !!!
http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx
于是实现了一个单例工厂 并且是线程安全的
#ifndef SINGLETONFACTORY_H
#define SINGLETONFACTORY_H
#include windows.h
#include <memory>
namespace
前段时间在网上看到了个的面试题,大概意思是如何在不使用锁和C++11的情况下,用C++实现线程安全的Singleton。
看到这个题目后,第一个想法是用Scott Meyer在《Effective C++》中提到的,在static成员函数中构造local static变量的方法来实现,但是经过一番查找、思考,才明白这种实现在某些情况下是有问题的。本文主要将从基本的单线程中的Singleton开始,慢慢讲述多线程与Singleton的那些事。
在单线程下,下面这个是常见的写法:
template<typename>
class Singleton
1. 创建一个基于对话框的应用程序。并增加如图所示控件;分别为3个进度条控件关联三个进度条类型的变量;并在对话框的初始化函数中,设定进度条的范围;为编辑框关联一个整型的变量;为12个按钮添加消息处理函数;
2. 定义结构体:用做线程函数的参数传递
typedef struct Threadinfo{
CProgressCtrl *progress;//进度条对象
int speed; //进度条速度
int pos; //进度条位置
} thread,*lpthread;
3. 为对话框增加三个句柄,用于标识各个线程;
HANDLE hThread1; //线程1线程句柄
HANDLE hThread2; //线程2线程句柄
HANDLE hThread3; //线程3线程句柄
在增加三个结构体类型的变量,用做线程函数的参数传递;
HANDLE hThread1; //线程1线程句柄
HANDLE hThread2; //线程2线程句柄
HANDLE hThread3; //线程3线程句柄
4. 新增一个静态的全局变量,用于记录所有线程的状态:static int GlobalVar=10000;
5. 声明并编写线程函数,注意只能有一个参数,且函数的返回值类型也是固定的;函数名可以自定义;
DWORD WINAPI ThreadFun(LPVOID pthread);//线程入口函数
6. 在启动按钮的消息处理函数中编写如下代码:
thread1.progress=&m_progress1;//进度条对象
thread1.speed=100;//速度
thread1.pos=0;//初始位置
hThread1=CreateThread(NULL,0,ThreadFun,&thread1;,0,0);//创建并开始线程
if (!hThread1)
MessageBox("创建线程失败");
7. 编写线程函数(一般是一个死循环,或者需要花费时间很长的算法!否者就失去了多线程的意义)
DWORD WINAPI ThreadFun(LPVOID pthread) //线程入口函数
lpthread temp=(lpthread)pthread;//参数强制转换为结构体类型
temp->progress->SetPos(temp->pos); //设置被传递过来的进度条的位置
while(temp->posspeed); /设置速度
temp->pos++; //增加进度
temp->progress->SetPos(temp->pos); //设置进度条的新位置
GlobalVar--;
if(temp->pos==20)
temp->pos=0; //进度条满则归0
return true;
8. 在挂起按钮函数中,编写如下代码:
if(SuspendThread(hThread1)==0xFFFFFFFF)
MessageBox("挂起失败!进程可能已经死亡或未创建!");
return;
9. 在执行按钮函数中,编写如下代码:
if(ResumeThread(hThread1)==0xFFFFFFFF)
MessageBox("执行失败!进程可能已经死亡或未创建!");
return;
10. 在停止按钮函数中,编写如下代码:
if(TerminateThread(hThread1,0))//前些终止线程
CloseHandle(hThread1);//销毁线程句柄
MessageBox("终止进程失败!");
11. 为应用程序添加WM_TIMER消息,实时更新全局变量的值到编辑框;
关于内存分配:由于static对象都是存储在全局数据段(对应可执行文件中的数据段),这些对象的内存都是在编译时就已经分配好了。
关于初始化:
C与C++表现得不同:由于C没有构造函数,因此初始化其实在编译时候已经完成;
而C++含有构造函数,需要调用对应的二进制代码,因此不可能在编译的时候完成。
对于全局对象、全局static对象、类static成员这些都是在main函数执行前调用构造函数进行初始...
阅读之前可以先回顾一下static的主要使用情况:
1、static方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。
但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可