zoukankan      html  css  js  c++  java
  • 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;
    }

    图像 4

    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;
    }

    图像 5

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

  • 相关阅读:
    事件的基本概念
    c# 语法 字符串内插
    tcp 的编程例子
    Action 语法的简介
    wcf 的小介绍
    Socket编程
    c# base new 等关键字基础
    虚函数和继承的关系
    arraylist,list ,数组区别
    Python爬虫-selenium模拟豆瓣电影鼠标下拉
  • 原文地址:https://www.cnblogs.com/monicalee/p/3848057.html
Copyright © 2011-2022 走看看