1.函数指针
1.1 普通成员函数指针包含类名信息以及const属性,指向具体函数是必须加上&符号。
#include <iostream> using namespace std; class Test{ public: void setValue(const string &s, int a){ s_ = s; a_ = a; } void print() const{ cout << s_ << endl << a_ << endl; } private: string s_; int a_; }; int main(int argc, const char *argv[]) { void (Test::*pfunc)(const string&, int) = &Test::setValue; void (Test::*pfunc1)()const = &Test::print; Test t; (t.*pfunc)("hello", 3); (t.*pfunc1)(); Test *t1 = new Test; (t1->*pfunc)("hello", 3); (t1->*pfunc1)(); delete t1; return 0; }
1.2 static 函数指针不包含类名, & 符号也不是必须。
#include <iostream> using namespace std; class Test{ public: static void print(){ cout << "hello world " << endl; } }; int main(int argc, const char *argv[]) { void(*funcPtr)() = &Test::print; funcPtr(); return 0; }
2.单例模式
2.1 将构造函数设为私有, 通过调用static 成员函数生成对象。此时通过多次调用static函数可以生成不同的对象。
#include <iostream> #include <string> #include <vector> using namespace std; /* *对象不唯一 */ class Singleton{ public: static Singleton *getInstance(){ Singleton *ps = new Singleton; return ps; } private: Singleton(){} }; int main(int argc, const char *argv[]) { Singleton *ps = Singleton::getInstance(); cout << ps << endl; Singleton *ps2 = Singleton::getInstance(); cout << ps2 << endl; return 0; }
2.2 为解决上述对象不唯一问题, 设置一静态变量,通过判断是否为空,去生成对象,看似保证了唯一性。
#include <iostream> #include <string> #include <vector> using namespace std; /* *多线程环境下存在竞态问题 */ class Singleton{ public: static Singleton *getInstance(){ if(pInstance_ == NULL){ pInstance_ = new Singleton; } return pInstance_; } private: Singleton(){} static Singleton *pInstance_; }; Singleton *Singleton::pInstance_ = NULL; int main(int argc, const char *argv[]) { Singleton *ps = Singleton::getInstance(); cout << ps << endl; Singleton *ps2 = Singleton::getInstance(); cout << ps2 << endl; return 0; }
2.3 但是上述代码在多线程环境下存在竞态问题(if 语句处,多个线程同时进入时,可以生成不同的对象)。 如下所示。
#include <iostream> #include <string> #include <vector> using namespace std; /* *多线程环境下存在竞态问题 */ class Singleton{ public: static Singleton *getInstance(){ if(pInstance_ == NULL){ sleep(2); pInstance_ = new Singleton; } return pInstance_; } private: Singleton(){} static Singleton *pInstance_; }; Singleton *Singleton::pInstance_ = NULL; void* threadFunc(void *arg){ Singleton *ps = Singleton::getInstance(); cout << ps << endl; } int main(int argc, const char *argv[]) { vector<pthread_t> vec(10); for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_create(&*it, NULL, threadFunc, NULL); } for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_join(*it, NULL); } return 0; }
2.4 为解决上述多线程竞态问题,我们每次检查指针前都上锁。这样就保证了对象在多线程环境下也是唯一的,如下所示。
#include <iostream> #include <vector> #include "mutexlock.h" using namespace std; /* *为了解决竞态问题 加锁 */ class Singleton{ public: static Singleton *getInstance(){ mutex_.lock(); if(pInstance_ == NULL){ sleep(2); pInstance_ = new Singleton; } mutex_.unlock(); return pInstance_; } private: Singleton(){} static Singleton *pInstance_; static Mutexlock mutex_; }; /* *static 成员变量在类的内部是声明 必须在类的外部定义 */ Singleton *Singleton::pInstance_ = NULL; Mutexlock Singleton::mutex_; void* threadFunc(void *arg){ Singleton *ps = Singleton::getInstance(); cout << ps << endl; } int main(int argc, const char *argv[]) { vector<pthread_t> vec(10); for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_create(&*it, NULL, threadFunc, NULL); } for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_join(*it, NULL); } return 0; }
2.4 上述程序每次获取对象都要加锁,造成了锁争用,使得效率降低,因此引用双重锁模式。
#include <iostream> #include <vector> #include "mutexlock.h" using namespace std; /* *每次调用都要征用锁 这是的效率降低 * 因此 采用双重锁 */ class Singleton{ public: static Singleton *getInstance(){ if(pInstance_ == NULL){ mutex_.lock(); if(pInstance_ == NULL){ sleep(2); pInstance_ = new Singleton; } mutex_.unlock(); } return pInstance_; } private: Singleton(){} static Singleton *pInstance_; static Mutexlock mutex_; }; /* *static 成员变量在类的内部是声明 必须在类的外部定义 */ Singleton *Singleton::pInstance_ = NULL; Mutexlock Singleton::mutex_; void* threadFunc(void *arg){ Singleton *ps = Singleton::getInstance(); cout << ps << endl; } int main(int argc, const char *argv[]) { vector<pthread_t> vec(10); for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_create(&*it, NULL, threadFunc, NULL); } for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_join(*it, NULL); } return 0; }
2.5 总结思路
单例模式的编写:
a) 构造函数设为私有,此时无法生成对象
b) 编写一个成员函数来生成对象,但是无法调用。
c) 将该函数设为static,此时可以生成对象,但是对象不唯一。
d) 添加一个static指针成员,仅当该指针为NULL(也就是第一次访问时)才去生成对象。
e) 但是此时的代码在多线程环境下存在竞态问题。
f) 于是我们每次检查指针前都要进行加锁。
g) 此时每次获取对象都要加锁,锁争用过多,影响效率,于是我们引入“双重锁”模式(Double Check Lock Pattern, DCLP)。这种模式采用了两重判断,其中内部的判断采用了锁,保证结果的正确性,外面的检查保证大部分线程不会进入争用锁。
h) 后面我们采用pthread_once 编写单例模式。