随笔 - 313  文章 - 29  评论 - 32  阅读 - 124万 

在阅读代码过程中,学到的东西很多,但是仔细想想看值得记下来的却没有几个。下面是几个chromium相对具有特色的代码片段。

一、RunLoop

扒掉层层继承和实现,RunLoop相关的基本逻辑代码如下:

class TaskRunner {
public:
	bool PostDelayedTask(const Location& from_here,
						   OnceClosure task,
						   base::TimeDelta delay){
		if (delay > base::TimeDelta())
		  return false;
		AutoLock auto_lock(tasks_lock_);
		pending_tasks_.push(std::move(task));
		return true;
	}
	bool ProcessTask(){
	    OnceClosure task;
		{
		  AutoLock auto_lock(tasks_lock_);
		  if (pending_tasks_.empty())
			return false;
		  task = std::move(pending_tasks_.front());
		  pending_tasks_.pop();
		}
		std::move(task).Run();
		return true;
	}
private:
	base::queue<OnceClosure> pending_tasks_;
}

class Delegate {
    void Run(bool application_tasks_allowed) {
		while (!should_quit_) {
			 simple_task_runner_->ProcessTask();
			 PlatformThread::YieldCurrentThread();
		}
	}
private:
	scoped_refptr<TaskRunner> simple_task_runner_ = MakeRefCounted<TaskRunner>();
}

class BASE_EXPORT RunLoop {
public:
	void RunLoop::Run(){
	  if (!BeforeRun())
		return;
	  delegate_->Run(application_tasks_allowed);
	  AfterRun();
	}
private:
	bool RunLoop::BeforeRun();
	void RunLoop::AfterRun();
	Delegate* delegate_;
}

int main() {
   ThreadTaskRunnerHandle::Get()->PostDelayedTask(
      FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
	RunLoop main_loop;
	main_loop.Run();
	return 0;
}

从上述代码中看出,chromium的事件处理逻辑与其他的开源项目并无不同。都是相同的几步:

  1. 通过类似PostDelayedTask之类的函数,把待执行的任务入队;
  2. 有一个Run函数循环读取任务队列,逐个执行队列中的任务;
  3. 操作任务队列的时候通过加锁来保证多线程场景下的数据一致性;

二、BindOnce和Bind

auto bf2 = std::bind(&A::Func, a, std::placeholders::_1, std::placeholders::_2); 
base::Bind([](base::WeakPtr<A> a) {}, weak_ptr_factory_.GetWeakPtr()));
base::BindOnce([](){}),

在Chromium中,BindOnceBind是用于绑定函数和成员函数的工具,它们与C++标准库中的std::bind在概念上有相似之处,但也存在显著的区别,特别是在设计目的、使用场景和实现细节上。

相同点

  1. 功能相似BindOnceBindstd::bind都允许你创建一个新的可调用对象,这个对象可以是绑定了一些参数的函数或成员函数的结果。这样做的好处是可以将函数与特定的数据或上下文关联起来,便于在不同的上下文中使用。

不同点

  1. 设计目的

    • std::bind:主要设计为C++标准库的一部分,旨在提供一种通用的绑定机制,可以用于各种函数和成员函数,以及支持部分参数绑定。
    • BindOnceBind:在Chromium中,BindBindOnce是专门设计用于异步编程和回调处理的。它们更专注于在异步环境中绑定和调用函数,尤其是与线程调度、任务队列等紧密相关。
  2. 异步支持

    • std::bind:不直接支持异步调用或回调处理。虽然你可以使用std::bind创建的可调用对象在异步环境中,但它本身不提供异步相关的特性。
    • BindOnceBindBindOnceBind在设计时考虑了异步环境,它们可以很容易地与Chromium的异步任务队列和线程池集成,使得异步回调的创建和处理更加方便。
  3. 参数绑定方式

    • std::bind:允许绑定函数的任意参数,甚至可以绑定多个参数,支持复杂的绑定逻辑。
    • BindOnce:顾名思义,它主要用于绑定那些只需要调用一次的函数。BindOnce绑定的参数是固定的,意味着一旦创建了绑定对象,就不能再次修改绑定的参数。
    • Bind:在Chromium中,Bind提供了比BindOnce更灵活的绑定选项,允许在创建时绑定部分参数,而其余参数在调用时再传入。
  4. 性能和资源管理

    • std::bind:在某些实现中,std::bind可能引入额外的开销,因为它需要在调用时动态解析绑定的参数和函数。
    • BindOnceBind:Chromium的BindOnceBind通常在设计时考虑了性能优化,尤其是针对异步调用场景,它们通常更高效,更少的运行时开销。
  5. 使用场景

    • std::bind:适用于需要通用绑定机制的场景,如在算法中传递预设参数的函数。
    • BindOnceBind:更适合用于异步编程、回调处理和线程调度等场景,尤其是在需要与Chromium的异步基础设施集成时。

综上所述,虽然std::bindBindOnceBind在功能上有所重叠,但它们的设计目标和使用场景各有侧重。std::bind更偏向于通用性,而BindOnceBind则更加专注于异步编程和资源管理,特别是在Chromium这样的高性能和多线程环境中。

三、scoped_refptr

scoped_refptr类似c++11之后支持的shared_ptr,重载了一些运算符,增加了引用计数。
区别在于scoped_refptr更注重于在高并发环境下的性能和线程安全性,而std::shared_ptr则提供了一个更通用、更灵活的解决方案,适用于广泛的使用场景。

template <class T>
class scoped_refptr {
 public:
  typedef T element_type;

  scoped_refptr() {}

  scoped_refptr(T* p) : ptr_(p) {
    if (ptr_)
      AddRef(ptr_);
  }

  // Copy constructor.
  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
    if (ptr_)
      AddRef(ptr_);
  }

  // Copy conversion constructor.
  template <typename U,
            typename = typename std::enable_if<
                std::is_convertible<U*, T*>::value>::type>
  scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
    if (ptr_)
      AddRef(ptr_);
  }

  // Move constructor. This is required in addition to the conversion
  // constructor below in order for clang to warn about pessimizing moves.
  scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }

  // Move conversion constructor.
  template <typename U,
            typename = typename std::enable_if<
                std::is_convertible<U*, T*>::value>::type>
  scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
    r.ptr_ = nullptr;
  }

  ~scoped_refptr() {
    static_assert(!base::subtle::IsRefCountPreferenceOverridden(
                      static_cast<T*>(nullptr), static_cast<T*>(nullptr)),
                  "It's unsafe to override the ref count preference."
                  " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE"
                  " from subclasses.");
    if (ptr_)
      Release(ptr_);
  }

  T* get() const { return ptr_; }

  T& operator*() const {
    DCHECK(ptr_);
    return *ptr_;
  }

  T* operator->() const {
    DCHECK(ptr_);
    return ptr_;
  }

  scoped_refptr<T>& operator=(T* p) {
    // AddRef first so that self assignment should work
    if (p)
      AddRef(p);
    T* old_ptr = ptr_;
    ptr_ = p;
    if (old_ptr)
      Release(old_ptr);
    return *this;
  }

  scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
    return *this = r.ptr_;
  }

  template <typename U>
  scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
    return *this = r.get();
  }

  scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
    scoped_refptr<T> tmp(std::move(r));
    tmp.swap(*this);
    return *this;
  }

  template <typename U>
  scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
    // We swap with a temporary variable to guarantee that |ptr_| is released
    // immediately. A naive implementation which swaps |this| and |r| would
    // unintentionally extend the lifetime of |ptr_| to at least the lifetime of
    // |r|.
    scoped_refptr<T> tmp(std::move(r));
    tmp.swap(*this);
    return *this;
  }

  void swap(scoped_refptr<T>& r) {
    T* tmp = ptr_;
    ptr_ = r.ptr_;
    r.ptr_ = tmp;
  }

  explicit operator bool() const { return ptr_ != nullptr; }

  template <typename U>
  bool operator==(const scoped_refptr<U>& rhs) const {
    return ptr_ == rhs.get();
  }

  template <typename U>
  bool operator!=(const scoped_refptr<U>& rhs) const {
    return !operator==(rhs);
  }

  template <typename U>
  bool operator<(const scoped_refptr<U>& rhs) const {
    return ptr_ < rhs.get();
  }

 protected:
  T* ptr_ = nullptr;

 private:
  template <typename U>
  friend scoped_refptr<U> base::AdoptRef(U*);

  scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}

  // Friend required for move constructors that set r.ptr_ to null.
  template <typename U>
  friend class scoped_refptr;

  // Non-inline helpers to allow:
  //     class Opaque;
  //     extern template class scoped_refptr<Opaque>;
  // Otherwise the compiler will complain that Opaque is an incomplete type.
  static void AddRef(T* ptr);
  static void Release(T* ptr);
};

// static
template <typename T>
void scoped_refptr<T>::AddRef(T* ptr) {
  ptr->AddRef();
}

// static
template <typename T>
void scoped_refptr<T>::Release(T* ptr) {
  ptr->Release();
}

template <typename T, typename U>
bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
  return lhs.get() == rhs;
}

template <typename T, typename U>
bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
  return lhs == rhs.get();
}

template <typename T>
bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
  return !static_cast<bool>(lhs);
}

template <typename T>
bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
  return !static_cast<bool>(rhs);
}

template <typename T, typename U>
bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
  return !operator==(lhs, rhs);
}

template <typename T, typename U>
bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
  return !operator==(lhs, rhs);
}

template <typename T>
bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
  return !operator==(lhs, null);
}

template <typename T>
bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
  return !operator==(null, rhs);
}

template <typename T>
std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
  return out << p.get();
}

template <typename T>
void swap(scoped_refptr<T>& lhs, scoped_refptr<T>& rhs) {
  lhs.swap(rhs);
}
posted on   步孤天  阅读(108)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示