0715-----C++Primer听课笔记-----------函数指针 、单例模式

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 编写单例模式。

0715-----C++Primer听课笔记-----------函数指针 、单例模式,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。