Chromium中的线程同步

1.Lock

线程互斥锁,使用方法:

Lock g_lock;
..
{
    AutoLock scope_lock(g_lock);
}

AutoLock的构造函数和析构函数里会调用Lock的acquire和release

  explicit AutoLock(Lock& lock) : lock_(lock) {
    lock_.Acquire();
  }

  ~AutoLock() {
    lock_.AssertAcquired();
    lock_.Release();
  }

Lock的acquire和release方法会调用LockImpl的Lock和Unlock方法,LockImpl由各个平台实现

  void Acquire() { lock_.Lock(); }
  void Release() { lock_.Unlock(); }

  internal::LockImpl lock_;

LockImpl在posix上的实现:

LockImpl::LockImpl() {
  pthread_mutexattr_t mta;
  int rv = pthread_mutexattr_init(&mta);
  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
......
  rv = pthread_mutex_init(&native_handle_, &mta);
  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
  rv = pthread_mutexattr_destroy(&mta);
  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
}
void LockImpl::Lock() {
  int rv = pthread_mutex_lock(&native_handle_);
  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
}

void LockImpl::Unlock() {
  int rv = pthread_mutex_unlock(&native_handle_);
  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
}

posix上的LockImpl使用pthread_mutex来实现

2. AtomicFlag

多线程安全的一个flag,有两个方法,Set和IsSet。

  void Set(); //设置标志

  bool IsSet() const; //检查标志是否设置

3.ConditionVariable

接口:

 ConditionVariable(Lock* user_lock);
  void Wait();
  void TimedWait(const TimeDelta& max_time);

  // signal all waiting thread  
  void Broadcast();
  // Signal() revives one waiting thread.
  void Signal();

wait:

  Lock lock;
  ConditionVariable cv(&lock);

  lock.Acquire();
  cv.Wait(); //wait退出后会自动获取锁

signal


//signal之前,获取锁
lock.Acquire()

cv.Signal()

4.Spin wait

用法:

SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(express);
SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(delta, expression)

宏,通过while循环等待,直到expression为真,或者1s(delta)超时

5. WaitableEvent

WaitableEvent(ResetPolicy reset_policy, InitialState initial_state);

  // Put the event in the un-signaled state.
  void Reset();

  // Put the event in the signaled state.  Causing any thread blocked on Wait
  // to be woken up.
  void Signal();

  // Returns true if the event is in the signaled state, else false.  If this
  // is not a manual reset event, then this test will cause a reset.
  bool IsSignaled();

  // Wait indefinitely for the event to be signaled. Wait's return "happens
  // after" |Signal| has completed. 
  void Wait();

  // Wait up until wait_delta has passed for the event to be signaled.  Returns
  // true if the event was signaled.
  //
  // TimedWait can synchronise its own destruction like |Wait|.
  bool TimedWait(const TimeDelta& wait_delta);

  // Wait up until end_time deadline has passed for the event to be signaled.
  // Return true if the event was signaled.
  //
  // TimedWaitUntil can synchronise its own destruction like |Wait|.
  bool TimedWaitUntil(const TimeTicks& end_time);

WaitableEvent使用WaitableEventKernel来实现。

  struct WaitableEventKernel :
      public RefCountedThreadSafe<WaitableEventKernel> {
   public:
    WaitableEventKernel(ResetPolicy reset_policy, InitialState initial_state);

    bool Dequeue(Waiter* waiter, void* tag);

    base::Lock lock_;
    const bool manual_reset_;
    bool signaled_;
    std::list<Waiter*> waiters_;

   private:
    friend class RefCountedThreadSafe<WaitableEventKernel>;
    ~WaitableEventKernel();
  };

WaitableEvent在posix平台上的实现

void WaitableEvent::Wait() {
  bool result = TimedWaitUntil(TimeTicks::Max());
  DCHECK(result) << "TimedWait() should never fail with infinite timeout";
}

bool WaitableEvent::TimedWait(const TimeDelta& wait_delta) {
  // TimeTicks takes care of overflow including the cases when wait_delta
  // is a maximum value.
  return TimedWaitUntil(TimeTicks::Now() + wait_delta);
}

bool WaitableEvent::TimedWaitUntil(const TimeTicks& end_time) {
  const bool finite_time = !end_time.is_max();

  kernel_->lock_.Acquire();
  if (kernel_->signaled_) {
    if (!kernel_->manual_reset_) {
      // In this case we were signaled when we had no waiters. Now that
      // someone has waited upon us, we can automatically reset.
      kernel_->signaled_ = false;
    }

    kernel_->lock_.Release();
    return true;
  }

  SyncWaiter sw;
  sw.lock()->Acquire();

  Enqueue(&sw);
  kernel_->lock_.Release();
  // We are violating locking order here by holding the SyncWaiter lock but not
  // the WaitableEvent lock. However, this is safe because we don't lock @lock_
  // again before unlocking it.

  for (;;) {
    const TimeTicks current_time(TimeTicks::Now());

    if (sw.fired() || (finite_time && current_time >= end_time)) {
      const bool return_value = sw.fired();

      // We can't acquire @lock_ before releasing the SyncWaiter lock (because
      // of locking order), however, in between the two a signal could be fired
      // and @sw would accept it, however we will still return false, so the
      // signal would be lost on an auto-reset WaitableEvent. Thus we call
      // Disable which makes sw::Fire return false.
      sw.Disable();
      sw.lock()->Release();

      // This is a bug that has been enshrined in the interface of
      // WaitableEvent now: |Dequeue| is called even when |sw.fired()| is true,
      // even though it'll always return false in that case. However, taking
      // the lock ensures that |Signal| has completed before we return and
      // means that a WaitableEvent can synchronise its own destruction.
      kernel_->lock_.Acquire();
      kernel_->Dequeue(&sw, &sw);
      kernel_->lock_.Release();

      return return_value;
    }

    if (finite_time) {
      const TimeDelta max_wait(end_time - current_time);
      sw.cv()->TimedWait(max_wait);
    } else {
      sw.cv()->Wait();
    }
  }
}

各种版本的Wait都调用到了TimedWaitUntil,在TimedWaitUntil里,先判断是否signal了,如果signal了,则返回true。

如果需要wait,则创建一个SyncWaiter,加入到kernel的waiter列表里。

void WaitableEvent::Reset() {
  base::AutoLock locked(kernel_->lock_);
  kernel_->signaled_ = false;
}

void WaitableEvent::Signal() {
  base::AutoLock locked(kernel_->lock_);

  if (kernel_->signaled_)
    return;

  if (kernel_->manual_reset_) {
    SignalAll();
    kernel_->signaled_ = true;
  } else {
    // In the case of auto reset, if no waiters were woken, we remain
    // signaled.
    if (!SignalOne())
      kernel_->signaled_ = true;
  }
}

bool WaitableEvent::IsSignaled() {
  base::AutoLock locked(kernel_->lock_);

  const bool result = kernel_->signaled_;
  if (result && !kernel_->manual_reset_)
    kernel_->signaled_ = false;
  return result;
}

当signal的时候,如果reset的模式是manual的,那么SignalAll,同时将kernel_->signaled_置为true,如果reset模式是Auto,则SignalOne,如果SingalOne返回True,则将kernel_->signaled_置为true。

bool WaitableEvent::SignalAll() {
  bool signaled_at_least_one = false;

  for (std::list<Waiter*>::iterator
       i = kernel_->waiters_.begin(); i != kernel_->waiters_.end(); ++i) {
    if ((*i)->Fire(this))
      signaled_at_least_one = true;
  }

  kernel_->waiters_.clear();
  return signaled_at_least_one;
}

bool WaitableEvent::SignalOne() {
  for (;;) {
    if (kernel_->waiters_.empty())
      return false;

    const bool r = (*kernel_->waiters_.begin())->Fire(this);
    kernel_->waiters_.pop_front();
    if (r)
      return true;
  }
}

推荐阅读更多精彩内容

  • 多个线程同时使用共享对象,这种情形被称为竞争条件(Race Condition),竞争条件是多线程环境中非常常见的...
    LH_晴阅读 2,390评论 0 1
  • 引用自多线程编程指南应用程序里面多个线程的存在引发了多个执行线程安全访问资源的潜在问题。两个线程同时修改同一资源有...
    Mitchell阅读 1,686评论 1 7
  • 名称 libev - 一个 C 编写的功能全面的高性能事件循环。 概要 示例程序 关于 libev Libev 是...
    hanpfei阅读 12,783评论 0 4
  • 【threading模块详解】 模块基本方法 该模块定了的方法如下:threading.active_count(...
    奕剑听雨阅读 665评论 0 0
  • 线程 操作系统线程理论 线程概念的引入背景 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有...
    go以恒阅读 1,351评论 0 6
  • 寒冷的冬天,要风度,也要有温度,高领毛衣绝对是首选。丰富的层次感,打造冬季暖男,成为寒冷都市里穿行的绅士。无论夹克...
    粒子的极简男士穿搭阅读 258评论 0 0
  • 电影既是商品,又是艺术。作为艺术,它的好坏是仁者见仁,智者见智的。但艺术水平有高下之分,不然就不会有那么多传世经典...
    乱弹阿琳阅读 357评论 0 2
  • 喜欢就争取,得到就珍惜,错过就忘记。人生也许不尽完美,正因为不完美,我们才需要不断地努力创造努力奋斗。时间就是生命...
    乾立风中阅读 34评论 0 0
  • 成功日志: 1.积极与人沟通,微笑和记住他人的名字,我主动打招呼,记住对方名字的有,西安姐姐,莫亚,向淇,瑞琪,艾...
    大萍_萍姐阅读 99评论 0 0
  • 这个世界上的智者有两种:一种是孩子,一种是老人。 孩子涉世不深,在他们眼中,社会和生活是很简单的,简单到一个人只需...
    彩虹姐夫阅读 160评论 0 0