美文网首页乱七八糟风暴
C++面向对象多线程学习笔记_同步对象

C++面向对象多线程学习笔记_同步对象

作者: manofmountain | 来源:发表于2017-07-08 10:59 被阅读6次

    通常而言,同步变量和条件变量声明为全局,所以,多个线程可以访问它们。虽然这需要使用同步变量的所有线程提供了方便,但它没有提供这些线程遵循的策略。这意味着线程可以按任意方式自由使用(或误用)同步变量。而且,传统同步变量没有为程序员提供实际的方法,将变量与需要同步的数据或设备直接关联。

    随着软件工程变得复杂,单个程序中源模块的数量逐渐增加。在大型多线程程序中,同步变量可能在一个源模块中全局声明,程序内的众多源模块都可以访问。跟踪哪一个源模块正锁定或取消锁定哪一个同步变量是一项繁琐而且容易出错的任务。而且,如果同步变量的数量很大,分清哪些变量与哪些数据对应使用变得更困难。

    使用面向对象技术去同步化变量。首先,互斥量或条件变量以及所有的相关系统服务都被封闭在一个接口类中。这意味着互斥量对线程内的所有函数或过程不再具有全局性。对互斥量的唯一的访问途径是通过类成员函数。其次,接口类与即将通过继承或复合同步的数据或设备直接关联。

    1. Mutext类

    class mutex{

    protected:

    pthread_mutex_t Mutex;

    general_exception SemException;

    public:

    mutex(void){

    if(ptrhead_mutex_init(&Mutex, NULL)){

    SemException.message("Could Not create Mutex");

    throw SemException;

    }

    ~mutex(void);

    void lock(void);

    void unlock(void);

    };

    使用mutex类与传统互斥量方法的重要区别在于互斥量类型的对象不会声明为自由漂浮或全局的对象。互斥量类型对象设计用作数据类或设备类的组件。它可以私有性地被一个数据或设备类继承,也可以嵌入另一个使用复合的类中。

    mutex用于保护该宿主类具有的所有临界区,该类决定部署互斥量的方式和时间。对象的用户不必担心同步化对象的使用,因为对象同步化自身。同步临界区的责任从对象的用户转而由对象的生产者承担。

    1.1 命名互斥量类

    命名互斥量可以被同一进程内的线程以及不同进程间的线程共享,而匿名互斥量则只用于执行同一进程中线程间的同步,它不与文件名字关联。在命名互斥量类中,我们可使用互斥量持续时间(mutex duration)作为一种技术来帮助我们避免死锁。

    class named_mutex:public mutex{

    protected:

    char MutexName[81];

    int initiallyOwned;

    public:

    named_mutex(void);

    named_mutex(char *MName, int Owned = 0);

    unsigned long lockDuration(void);

    void lockDuration(unsigned long Dur);

    };

    1.2 同步和依赖性关系

    同步关系相关的控制机制为:互斥量、条件变量与条件断言;依赖性关系相关的控制机制为:线程间通信和进程间通信。

    面向对象编程的一个基本概念即类通过方法(method)调控对数据组件的所有访问。

    我们的目标是通过面向对象技术管理竞争条件和死锁,同样我们希望将实现并发的责任转移到类、类库以及应用框架级别,减少并发和同步编程的一些复杂性。

    1.3 表示条件的类

    class event_mutex{

    protected:

    LPSECURITY_ATTRIBUTES SecurityPtr;

    HANDLE EventMutex;

    char MutexName[81];

    int InitiallySet;

    general_exception EventException;

    unsigned long EventWait;

    unsigned int AccessLevel;

    int ManualReset;

    public:

    event_mutex(char *MName, unsigned int Initial = 0, unsigned long Reset,

    LPSECURITY_ATTRUBUTES Secure){

    EventMutex = CreateEvent(Secure, Reset, Initial, Mname);

    if(!EventMutex){

    EventException.message("Could not create Event Semaphore");

    throw EventException;

    }

    if(MName !=NULL){

    strcpy(MutextName, MName);

    }

    EventWait = INFINITE;

    }

    event_mutex(char *MName, unsigned int Access, unsigned long Inherit){

    EventMutex = OpenEvent(Access, Inherit, MName);

    if(!EventMutex){

    EventException.message("Could not create Event Semaphore");

    throw EventException;

    }

    if(MName != NULL){

    strcpy(MutexName, Mname);

    }

    EventWait = INFINITE;

    }

    void postEvent(void){

    SetEvent(EventMutex);

    }

    void waitEvent(void){

    WaitForSingleObject(EventMutex, EventWait);

    }

    void resetEvent(void){

    ResetEvent(EventMutex);

    }

    ~event_mutex(void){

    if(!CloseHandle(EventMutex)){

    EventException.message("Could not close mutex");

    throw EventException;

    }

    }

    };

    其中使用多构造函数的模式使得客户/服务器多进程处理更方便,它避免程序员必须编写重复代码之劳。

    1.4 等待多个事件或互斥量

    另一种类型的条件变量就是包含多个事件或互斥量的事件互斥量(event mutex)。阻塞于这些多个等待变量的线程的线程可能等待所有事件,在处理过程继续之前,互斥量根据这些事件来设置。

    class multiple_event_mutex{

    protected:

    char MutexName[81];

    SEMRECORD *ConditionList;

    int EventNumber;

    long int WaitSelection;

    HEV EventMutex;

    MultipleEventMutex;

    general_exception EventException;

    int Duration;

    public:

    multiple_event_mutex(char *MName, int ENum, long int WaitType, int Initial){

    int N;

    EventNumber = ENum;

    ConditionList = new SEMRECORD[ENum];

    for(N = 0; N < ENum; ++N){

    if(DosCreateEventSem(NULL, &EventMutex, 0, Imitial)){

    EventException.message("Could not create event semaphore");

    throw EventException;

    }

    ConditionList[N].hsemCur = &EventMutex;

    ConditionList[N].ulUser = N;

    }

    if(DosCreateMuxWaitSem(MName, &MultipleEventMutex, sizeof(ConditionList), ConditionList, WaitType)){

    EventException.message("Could not create multiple event semaphore.");

    throw EventException;

    }

    }

    multiple_event_mutex(char *MName){

    if(DosOpenMuxWaitSem(MName, &MultipleEventMutex)){

    EventException.message("Could not open event semaphore");

    throw EventException;

    }

    }

    ~multiple_event_mutex(void){

    if(DosCloseMuxWaitSem(MultipleEventMutex)){

    EventException.message("Could not close event semaphore");

    throw EventException;

    }

    delete ConditionList;

    }

    int duration(int x){

    return Duration;

    }

    void duration(int x){

    Duration = X;

    }

    void postEvent(int x){

    EventMutex = (HEV) ConditionList[x].hsemCur;

    DosPostEventSem(EventMutex);

    }

    void waitEvents(void){

    unsigned long user;

    DosWaitMuxWaitSem(MultipleEventMutex, SEM_INDEFINITE_WAIT, &User);

    }

    };

    针对复杂事务处理,有一套标准可以衡量特定事务是否让数据库处于一致的状态。其中一个标准就是ACID测试。缩写ACID代表原子性(atomicity)、一致性(consistency),孤立性(isolation)以及持久性(durability)。

    };

    1.5 小结

    同步对象可以通过设计封装了系统API的接口类(Inteface class)来创建。一旦创建了同步类(synchronization class),在那些被多线程或多进程并发或同步使用的任何类型C++类中,可以添加以上同步类。在某个类中包含同步类或者使用复合、包容或继承来实现。建议只让类中的直接成员访问同步类,只有在非常特定的条件下才允许同步类被派生类访问。

    在try块中放入声明对象的优点在于,抛出异常时自动调用它们的析构函数。应该用面向对象技术来关联同步机制与即将同步的对象或设备,也就是说在任何可能的地方,避免自由漂浮的同步对象。使用类聚集(class aggregation)来连接同步类(synchronization class)与数据(data class)和设备类(device class)。

    相关文章

      网友评论

        本文标题:C++面向对象多线程学习笔记_同步对象

        本文链接:https://www.haomeiwen.com/subject/lmvdhxtx.html