blob: 46a70c0beb059f9bd068ab35423ad21684b55710 [file] [log] [blame]
// 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/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/string_piece.h"
#include "base/task/sequence_manager/sequence_manager.h"
#include "base/task/sequence_manager/task_queue.h"
#include "base/task/single_thread_task_runner.h"
enum class TaskType : unsigned char {
kSource1 = 1,
kSource2 = 2,
};
enum class TaskPriority : base::sequence_manager::TaskQueue::QueuePriority {
kHighPriority = 0,
kNormalPriority = 1,
kNumPriorities = 2,
};
void Task(base::StringPiece tq, int task_number) {
if (tq == "A") {
LOG(INFO) << "TaskQueue(" << tq << "): " << task_number;
} else {
LOG(INFO) << " TaskQueue(" << tq << "): " << task_number;
}
}
void QuitTask(base::OnceClosure quit_closure) {
LOG(INFO) << "Quittin' time!";
std::move(quit_closure).Run();
}
int main() {
base::PlatformThread::SetName("SchedulingDemoMain");
std::unique_ptr<base::MessagePump> pump =
base::MessagePump::Create(base::MessagePumpType::DEFAULT);
base::sequence_manager::SequenceManager::PrioritySettings priority_settings(
TaskPriority::kNumPriorities, TaskPriority::kNormalPriority);
// Create the main thread's SequenceManager; it will choose which of the two
// below TaskQueues will be served at each spin of the loop, based on their
// priority.
std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager =
base::sequence_manager::CreateSequenceManagerOnCurrentThreadWithPump(
std::move(pump),
base::sequence_manager::SequenceManager::Settings::Builder()
.SetPrioritySettings(std::move(priority_settings))
.Build());
// Create two TaskQueues that feed into the main thread's SequenceManager,
// each with a different priority to demonstrate that TaskQueue is the
// principal unit of ordering, and that tasks across queues don't have to run
// in posting-order, while non-delayed tasks posted to the same queue are
// always run in FIFO order.
base::sequence_manager::TaskQueue::Handle tq_a =
sequence_manager->CreateTaskQueue(base::sequence_manager::TaskQueue::Spec(
base::sequence_manager::QueueName::TEST_TQ));
tq_a->SetQueuePriority(TaskPriority::kNormalPriority);
base::sequence_manager::TaskQueue::Handle tq_b =
sequence_manager->CreateTaskQueue(base::sequence_manager::TaskQueue::Spec(
base::sequence_manager::QueueName::TEST2_TQ));
tq_b->SetQueuePriority(TaskPriority::kHighPriority);
// Get TaskRunners for both TaskQueues.
scoped_refptr<base::SingleThreadTaskRunner> a_runner_1 =
tq_a->CreateTaskRunner(static_cast<int>(TaskType::kSource1));
sequence_manager->SetDefaultTaskRunner(a_runner_1);
scoped_refptr<base::SingleThreadTaskRunner> a_runner_2 =
tq_a->CreateTaskRunner(static_cast<int>(TaskType::kSource2));
scoped_refptr<base::SingleThreadTaskRunner> b_runner =
tq_b->CreateTaskRunner(static_cast<int>(TaskType::kSource2));
base::RunLoop run_loop;
// This example shows that the TaskRunner you choose to post a task with to a
// TaskQueue doesn't affect the ordering of the tasks in the queue. It is
// TaskQueue that is the principal unit of ordering, not TaskRunner; all tasks
// in a queue run in FIFO order with respect to each other, but tasks *across*
// queues are run in queue priority order. We post all of the tasks to `tq_a`
// before posting any to `tq_b`, but observe that `tq_b` tasks run first due
// to priority.
for (int i = 1; i <= 20;) {
a_runner_1->PostTask(FROM_HERE, base::BindOnce(&Task, "A", i++));
a_runner_2->PostTask(FROM_HERE, base::BindOnce(&Task, "A", i++));
}
for (int i = 1; i <= 20; ++i) {
b_runner->PostTask(FROM_HERE, base::BindOnce(&Task, "B", i));
}
a_runner_1->PostDelayedTask(FROM_HERE,
base::BindOnce(&QuitTask, run_loop.QuitClosure()),
base::Seconds(1));
run_loop.Run();
return 0;
}