910e62b5创建于 1月15日历史提交
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/logging.h"
#include "base/message_loop/message_pump.h"
#include "base/run_loop.h"
#include "base/task/sequence_manager/sequence_manager.h"
#include "base/task/sequence_manager/sequence_manager_impl.h"  // For IOThreadDelegate.
#include "base/task/sequence_manager/task_queue.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"

// For this example, these are global so that each task running on each thread
// can easily grab the *other* thread's task runner to post continuation tasks
// to.
static scoped_refptr<base::SingleThreadTaskRunner> g_main_thread_task_runner;
static scoped_refptr<base::SingleThreadTaskRunner> g_io_thread_task_runner;

void RunOnIOThread();

void RunOnUIThread() {
  LOG(INFO) << "RunOnUIThread()";
  g_io_thread_task_runner->PostDelayedTask(
      FROM_HERE, base::BindOnce(&RunOnIOThread), base::Seconds(1));
}

void RunOnIOThread() {
  LOG(INFO) << "RunOnIOThread()";
  g_main_thread_task_runner->PostDelayedTask(
      FROM_HERE, base::BindOnce(&RunOnUIThread), base::Seconds(1));
}

// In this example we're simulating Chromium's UI/IO thread architecture in a
// simplified way. The `IOThreadDelegate` represents the physical "IO" thread
// that each Chromium process has, running alongside the main thread. It is
// similar to `content::BrowserIOThreadDelegate`, for example.
class IOThreadDelegate : public base::Thread::Delegate {
 public:
  IOThreadDelegate() {
    // Create an unbound SequenceManager{Impl}. It will be bound in
    // `BindToCurrentThread()` on the new physical thread, once it starts
    // running.
    owned_sequence_manager_ =
        base::sequence_manager::CreateUnboundSequenceManager();
    task_queue_ = owned_sequence_manager_->CreateTaskQueue(
        base::sequence_manager::TaskQueue::Spec(
            base::sequence_manager::TaskQueue::Spec(
                base::sequence_manager::QueueName::IO_DEFAULT_TQ)));
    default_task_runner_ = task_queue_->task_runner();
    owned_sequence_manager_->SetDefaultTaskRunner(default_task_runner_);
    // Set the global TaskRunner-to-this-thread, so that the main thread can
    // post tasks to the IO thread.
    g_io_thread_task_runner = default_task_runner_;
  }

  // base::Thread::Delegate implementation.
  // This is similar to i.e.,
  // `content::BrowserIOThreadDelegate::BindToCurrentThread()`, and is the first
  // function to run on the new physical thread.
  void BindToCurrentThread() override {
    owned_sequence_manager_->BindToMessagePump(
        base::MessagePump::Create(base::MessagePumpType::IO));
    owned_sequence_manager_->SetDefaultTaskRunner(GetDefaultTaskRunner());
  }
  scoped_refptr<base::SingleThreadTaskRunner> GetDefaultTaskRunner() override {
    return default_task_runner_;
  }

  void AddTaskObserver(base::TaskObserver* observer) override {
    owned_sequence_manager_->AddTaskObserver(observer);
  }

 private:
  std::unique_ptr<base::sequence_manager::SequenceManager>
      owned_sequence_manager_;
  base::sequence_manager::TaskQueue::Handle task_queue_;
  scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
};

int main() {
  base::PlatformThread::SetName("SchedulingDemoMain");

  std::unique_ptr<base::MessagePump> pump =
      base::MessagePump::Create(base::MessagePumpType::UI);

  std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager =
      base::sequence_manager::CreateSequenceManagerOnCurrentThreadWithPump(
          std::move(pump));

  // Create a default TaskQueue that feeds into the SequenceManager.
  base::sequence_manager::TaskQueue::Handle main_task_queue =
      sequence_manager->CreateTaskQueue(base::sequence_manager::TaskQueue::Spec(
          base::sequence_manager::TaskQueue::Spec(
              base::sequence_manager::QueueName::DEFAULT_TQ)));

  // Get a default TaskRunner for the main (UI) thread.
  scoped_refptr<base::SingleThreadTaskRunner> default_task_runner =
      main_task_queue->task_runner();
  sequence_manager->SetDefaultTaskRunner(default_task_runner);

  // Set the global TaskRunner-to-this-thread, so that the IO thread can post
  // tasks to the main thread.
  g_main_thread_task_runner = default_task_runner;

  // Create an IO thread to run alongside the main thread.
  std::unique_ptr<IOThreadDelegate> delegate =
      std::make_unique<IOThreadDelegate>();
  base::Thread io_thread("IOThread");
  base::Thread::Options options;
  options.delegate = std::move(delegate);
  if (!io_thread.StartWithOptions(std::move(options))) {
    LOG(FATAL) << "The thread failed to start!";
  }
  // END create a new thread.

  base::RunLoop run_loop;
  g_main_thread_task_runner->PostTask(FROM_HERE,
                                      base::BindOnce(&RunOnUIThread));
  g_main_thread_task_runner->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
                                             base::Seconds(10));
  run_loop.Run();
  return 0;
}