browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

一个对接口调用自动加锁的代理类

Posted by on 2014 年 05 月 29 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

有的时候,我们会遇到类似下面这样的案例:

  1. 持有一个线程不安全的接口指针;
  2. 接口方法的调用是在跨线程的场景下进行的,因此需要对每个调用都加锁;
  3. 这个接口的方法很多,这就意味着对每个调用都需要编写加锁/解锁的代码段——显然,这将耗费太多的代码篇幅和编码时间。

简单说来,我们需要某个技巧来最大限度地规避上述接口方法调用时的手动加锁/解锁操作。不过,按照最近比较流行的一个说法,就是首先你要有个女朋友锁……

1
2
3
4
5
6
7
8
9
10
11
12
class NullLock
{
public:
    void Lock(void)
    {
        std::cout << "Lock." << std::endl;
    }
    void Unlock(void)
    {
        std::cout << "Unlock." << std::endl;
    }
};

就这样吧,此处无锁胜有锁。

接下来,我们还是把目光转向最关键的问题:如何对每个调用都自动进行加锁/解锁的操作?其实,这个需求本身其实已经包含了它的解决方案:

  1. 对于加锁/解锁的自动机制而言,用构造函数和析构函数来进行守护是再合适不过了。
  2. 为了准确捕获接口方法的每个调用,可以借鉴智能指针的设计思想,使用代理类来在 operator-> 中插入自动锁。

分析完毕。那么以下是我的解决方案,一个名为 LockPtr 的模板类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
template <class T, class Lock>
class LockPtr : public std::auto_ptr<T>
{
public:
    template <class T, class Lock>
    class AutoLock
    {
    public:
        AutoLock(T *p, Lock &lock) : m_ptr(p), m_lock(lock)
        {
            m_lock.Lock();
        }
        ~AutoLock(void)
        {
            m_lock.Unlock();
        }
        T* operator->()
        {
            return m_ptr;
        }
    private:
        T *m_ptr;
        Lock &m_lock;
    };
public:
    LockPtr(T *pT) : std::auto_ptr<T>(pT)
    {
        // Nothing
    }
    AutoLock<T, Lock> operator->()
    {
        return AutoLock<T, Lock>(get(), m_lock);
    }
private:
    Lock m_lock;
};

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo
{
public:
    void foo(void)
    {
        std::cout << "Foo::foo" << std::endl;
    }
};
 
int main(void)
{
    LockPtr<Foo, NullLock> p(new Foo);
    p->foo();
    return 0;
}

运行结果也完全达到了预期:

Lock.
Foo::foo
Unlock.

LockPtr 的代码已提交至 GitHub

订阅本站

没有评论

(Required)
(Required, will not be published)