并发控制
并发控制指的是当多个用户同时更新行时,用于保护数据库完整性的各种技术。并发机制不正确可能导致脏读、幻读和不可重复读等此类问题。并发控制的目的是保证一个用户的工作不会对另一个用户的工作产生不合理的影响。在某些情况下,这些措施保证了当用户和其他用户一起操作时,所得的结果和她单独操作时的结果是一样的。在另一些情况下,这表示用户的工作按预定的方式受其他用户的影响。
ACE Lock类
互斥体用于保护共享的易变代码,也就是全局或静态数据。这样的数据必须通过互斥体进行保护,以防止它们在多个线程同时访问时损坏。在ACE中可以通过ACE_Thread_Mutex实现线程的访问互斥。
ACE_Thread_Mutex主要有两个方法:1. acquire():用来获取互斥体,如果无法获取,将阻塞至获取到为止。2. release():用来释放互斥体,从而使自己或者其它线程能够获取互斥体。当线程要访问共享资源时,首先调用acquire()方法获取互斥体,从而获取对改互斥体所保护的共享资源的唯一访问权限,访问结束时调用释放互斥体,使得其它线程能获取共享资源的访问权限。在此例中,本例Thread2的打印消息在Thread1之前,但由于Thread1先获得互斥体,故Thread2只有待Thread1结束后才能进入临界区。
Guard类
为改善应用的健壮性,ACE同步机制有效地利用C++类构造器和析构器的语义来确保Mutex锁被自动获取和释放。Guard类是最基本的守卫机制。 Guard只能帮你自动加解锁,并不能解决死锁问题,Guard是在Guard变量析构时解锁,如果在同一函数中两次对同一互斥体变量使用Guard要注意其对象生命周期,否则容易造成死锁。
Condition类
ACE Condition类属(条件变量)提供风格与互斥体、读者/作者锁和计数信号量不同的锁定机制。当持有锁的线程在临界区执行代码时,这三种机制让协作线程进行等待。相反,条件变量通常被一个线程用于使自己等待,直到一个涉及共享数据的条件表达式到达特定的状态。当另外的协作线程指示共享数据的状态已发生变化,调度器就唤醒一个在该条件变量上挂起的线程。于是新唤醒的线程重新对它的条件表达式进行求值,如果共享数据已到达合适状态,就恢复处理。该对象有两个常用方法:signal():向使用该条件变量的其它线程发送唤醒信号。wait():查询是否满足条件,如果满足,则继续往下执行;如果不满足条件,主线程就等待在此条件变量上。
这个例子中,首先创建了一个生产者线程worker和一个消费者线程eater,消费者线程执行比生产者快,两个线程不加限制并发执行会导致先消费,后生产的情况(只是加互斥锁也不能很好的解决,以为无法保证生产者一定先获得互斥体)。所以这里通过条件变量的通知方式保证线程的顺序执行:消费者线程获取互斥体,等待条件满足(生产者生产了食品)。同时释放互斥体,进入休眠状态。生产者获取互斥体(虽然是消费者先获取的互斥体,但消费者调用的wait函数会释放消费者的互斥体),生产商品后,通过条件变量发送信号(调用signal函数)通知消费者生产完成,结束生产过程,释放互斥体。消费者收到信号后,重新获取互斥体,完成消费过程。条件变量必须和互斥体一起使用,也就是说使用前必须加锁(调用互斥体acquire函数),使用完后需释放互斥体。条件变量中的wait()和signal()成对使用的话,必须保证wait()函数在signal()之前执行,这样才能保证wait()能收到条件满足通知,不至于一直等待下去,形成死锁(worker线程中的第一句话就是起的这个作用)。