2012年5月27日星期日

锁,编程你需要知道的!

锁的归纳
     -- windows系统编程的锁(Linux系统类似)

lock & unlock


# 锁的概念
当然,在此要讲述的锁并非生活中的锁(门锁,车锁等)。而是编程世界的锁。
锁,在并发程序逻辑中保证某操作的同步性的一利器。该并发包括多线程与多进程(的线程)两种情况。
举个例子说明情况吧,如下:

Lock lock;
Job job;

func1()
{// run in thread1 or program1.
     do_lock(lock);
     handle(job);
     ... 
}

func2()
{// run in thread2 or program2.
     do_lock(lock);
     handle(job);
     ... 
}

这样,借助锁变量lock的同步操作,就可以保证处理事务job的原子性。在同一时刻只允许在一个地方处理事务job。
若时刻t,程序先进入func1执行handle(job)但未完成时,lock已被加锁,那么同时再进入func2时候由于lock已被加锁,导致程序会停在等待lock被解锁。
直到执行handle(job)完成,func2得到锁了才开始执行handle(job)。反之亦然。

# 锁的抽象设计

锁,最关键的两个操作:
a. 加锁
b. 解锁
而其构造函数,需根据不同实现方案而定。其他的操作可根据不同需求情况而定。

一般情况,锁都不希望被设计成具有可复制性。

比如我之前设计过的锁,示例如下:
class locker
{
    LIMIT_COPY_AND_ASSIGN_CTOR(locker)

public:
    locker();
     ... other constructor ...
    virtual ~locker() {}
     // main func
    virtual bool lock() = 0;
    virtual bool unlock() = 0;

     // extended func
    virtual bool is_valid() const;
    HANDLE handle() const;
    string_t name() const;
    int get_wait_ret() const;
    unsigned get_wait_time() const;
    void set_wait_time(unsigned wait_time);
    int error() const;
     ... other ...

protected:
    ... member var ...
};

在面向对象编程,我们一般把加锁与解锁的操作对应到一起,设计一个类型将两者包含,一个在构造函数,一个在析构函数。这样做可以保证加锁与解锁的对称性,不管程序中途返回或抛出异常,锁都是安全的。其设计很简单,如下:


template
 <class _Locker>
class scoped_lock_t
{
public:
    scoped_lock_t( _Locker& mutex_obj )
        : _locker(mutex_obj)
    {
        bool lock_ret = _locker.lock();
        assert (lock_ret);
    }
    ~scoped_lock_t()
    {
        bool lock_ret = _locker.unlock();
        assert (lock_ret);
    }
private:
    _Locker& _locker;
};

typedef scoped_lock_t<locker> scoped_lock;


锁的实现方案
     --(windows系统编程实现方案)
1.  互斥变量
Mutex functionDescription
CreateMutexCreates or opens a named or unnamed mutex object.
CreateMutexExCreates or opens a named or unnamed mutex object and returns a handle to the object.
OpenMutexOpens an existing named mutex object.
ReleaseMutexReleases ownership of the specified mutex object.

2. 事件
Event functionDescription
CreateEventCreates or opens a named or unnamed event object.
CreateEventExCreates or opens a named or unnamed event object and returns a handle to the object.
OpenEventOpens an existing named event object.
PulseEventSets the specified event object to the signaled state and then resets it to the nonsignaled state after releasing the appropriate number of waiting threads.
ResetEventSets the specified event object to the nonsignaled state.
SetEventSets the specified event object to the signaled state.

3. 信号量
Semaphore functionDescription
CreateSemaphoreCreates or opens a named or unnamed semaphore object.
CreateSemaphoreExCreates or opens a named or unnamed semaphore object and returns a handle to the object.
OpenSemaphoreOpens an existing named semaphore object.
ReleaseSemaphoreIncreases the count of the specified semaphore object by a specified amount.

4. 临界区变量
Critical section functionDescription
DeleteCriticalSectionReleases all resources used by an unowned critical section object.
EnterCriticalSectionWaits for ownership of the specified critical section object.
InitializeCriticalSectionInitializes a critical section object.
InitializeCriticalSectionAndSpinCountInitializes a critical section object and sets the spin count for the critical section.
InitializeCriticalSectionExInitializes a critical section object with a spin count and optional flags.
LeaveCriticalSectionReleases ownership of the specified critical section object.
SetCriticalSectionSpinCountSets the spin count for the specified critical section.
TryEnterCriticalSectionAttempts to enter a critical section without blocking.

还有其他,详见msdn


线程间的加锁
以上描述到实现方案,都适用于线程间的加锁操作。但是不同锁有不同的用法,效率也不同。
信号量与其他三者的用法不同,其不仅仅具备加锁解锁的功能。信号量对象对线程的同步方式不同于其他,信号量允许多个线程同时使用共享资源 ,这与操作系统中的PV操作相同。

注意仅限于线程间使用的锁,其效率较高,如临界区对象。

之间区别的更详细说明可以参考这里这里

进程间的加锁
上述四种具体的实现方案,除了临界区对象,其他三者都适用于进程间的加锁操作,并且三者创建的对象都是windows系统的内核对象。由于属于内核对象那么系统需要在内核层负责管理这些对象的属性与操作,所以这三者内核对象加锁(解锁)的效率要低于临界区对象。

锁的效率问题
不同锁之间有不同的效率问题。只要你明确该点,且理清并发场景与锁的具体使用情况。
当然,要是无需加锁操作就可以解决问题的实现方案,多半情况下就是最高效的方案了(哦,是对比于加锁方案)。

# 链接


1 条评论: