Simple example

Below you can find source code of a simple example that uses main features of the libbase library. This example is located in the /examples/simple/ directory in the repository and - if enabled - will be built along the libbase library itself.

CMakeLists.txt
 1add_executable(simple "")
 2
 3target_compile_options(simple
 4  PRIVATE
 5    ${LIBBASE_COMPILE_FLAGS}
 6)
 7
 8target_link_libraries(simple
 9  PRIVATE
10    libbase
11)
12
13target_sources(simple
14  PRIVATE
15    main.cc
16)
main.cc
  1#include <thread>
  2
  3#include "base/bind.h"
  4#include "base/init.h"
  5#include "base/logging.h"
  6#include "base/synchronization/auto_signaller.h"
  7#include "base/synchronization/waitable_event.h"
  8#include "base/threading/thread.h"
  9#include "base/threading/thread_pool.h"
 10#include "base/timer/elapsed_timer.h"
 11#include "base/trace_event/trace_event.h"
 12#include "base/trace_event/trace_flow.h"
 13#include "base/trace_event/trace_flush.h"
 14
 15namespace {
 16std::shared_ptr<base::SequencedTaskRunner> tr1;
 17std::shared_ptr<base::SequencedTaskRunner> tr2;
 18}  // namespace
 19
 20void Task1(std::shared_ptr<base::TaskRunner> current,
 21           std::shared_ptr<base::TaskRunner> next,
 22           base::WaitableEvent* five_left_event,
 23           base::AutoSignaller finished_event,
 24           int n) {
 25  CHECK_GE(n, 0) << "`n` must be greater or equal to 0";
 26  TRACE_EVENT("thread_example", "task1", "n", std::to_string(n));
 27  TRACE_EVENT_WITH_FLOW_STEP("thread_example", "flow:ThreadExample", &tr1);
 28  LOG(INFO) << __FUNCTION__ << "() Writing from thread "
 29            << std::this_thread::get_id() << " with n=" << n
 30            << "(tr1: " << tr1->RunsTasksInCurrentSequence()
 31            << ", tr2: " << tr2->RunsTasksInCurrentSequence() << ")"
 32            << std::endl;
 33
 34  if (n == 5) {
 35    five_left_event->Signal();
 36  }
 37  if (n > 0) {
 38    next->PostTask(FROM_HERE,
 39                   base::BindOnce(&Task1, next, current, five_left_event,
 40                                  std::move(finished_event), n - 1));
 41  }
 42}
 43
 44void ThreadExample() {
 45  TRACE_EVENT("thread_example", "ThreadExample");
 46  base::Thread t1{};
 47  base::Thread t2{};
 48
 49  t1.Start();
 50  t2.Start();
 51
 52  tr1 = t1.TaskRunner();
 53  tr2 = t2.TaskRunner();
 54
 55  base::WaitableEvent five_left_event{};
 56  base::WaitableEvent finished_event{};
 57
 58  {
 59    TRACE_EVENT("thread_example", "Async work start");
 60    TRACE_EVENT_WITH_FLOW_BEGIN("thread_example", "flow:ThreadExample", &tr1);
 61    tr1->PostTask(FROM_HERE,
 62                  base::BindOnce(&Task1, tr1, tr2, &five_left_event,
 63                                 base::AutoSignaller{&finished_event}, 10));
 64  }
 65
 66  five_left_event.Wait();
 67  LOG(INFO) << __FUNCTION__ << "() (at most 5 calls left)...";
 68  finished_event.Wait();
 69  LOG(INFO) << __FUNCTION__ << "() finished";
 70
 71  {
 72    TRACE_EVENT_WITH_FLOW_END("thread_example", "flow:ThreadExample", &tr1);
 73    TRACE_EVENT("thread_example", "Async work done");
 74  }
 75  t2.Stop();
 76  t1.Stop();
 77}
 78
 79void ThreadDelayedExample() {
 80  base::Thread thread{};
 81  base::WaitableEvent finished_event{};
 82
 83  thread.Start();
 84
 85  thread.TaskRunner()->PostDelayedTask(
 86      FROM_HERE,
 87      base::BindOnce(
 88          []([[maybe_unused]] base::AutoSignaller finished_signaller) {
 89            LOG(INFO)
 90                << "ThreadDelayedExample() delayed (300ms) task executing";
 91          },
 92          base::AutoSignaller{&finished_event}),
 93      base::Milliseconds(300));
 94
 95  thread.TaskRunner()->PostTask(
 96      FROM_HERE, base::BindOnce([]() {
 97        LOG(INFO) << "ThreadDelayedExample() non-delayed task executing";
 98      }));
 99
100  thread.TaskRunner()->PostDelayedTask(
101      FROM_HERE, base::BindOnce([]() {
102        LOG(INFO) << "ThreadDelayedExample() delayed (100ms) task executing";
103      }),
104      base::Milliseconds(100));
105
106  finished_event.Wait();
107  LOG(INFO) << __FUNCTION__ << "() finished";
108
109  thread.Stop();
110}
111
112void ThreadPoolNonSequencedExample() {
113  base::ThreadPool pool{1};
114  pool.Start();
115
116  auto generic_tr1 = pool.GetTaskRunner();
117
118  pool.Stop();
119}
120
121void ThreadPoolSequencedExample() {
122  base::ThreadPool pool{4};
123  pool.Start();
124
125  auto sequenced_tr1 = pool.CreateSequencedTaskRunner();
126  auto sequenced_tr2 = pool.CreateSequencedTaskRunner();
127
128  pool.Stop();
129}
130
131void ThreadPoolSingleThreadExample() {
132  base::ThreadPool pool{4};
133  pool.Start();
134
135  auto single_thread_tr1 = pool.CreateSingleThreadTaskRunner();
136
137  pool.Stop();
138}
139
140int main(int argc, char* argv[]) {
141  base::Initialize(argc, argv, base::InitOptions{});
142
143  const auto timer = base::ElapsedTimer{};
144
145  ThreadExample();
146  ThreadDelayedExample();
147  ThreadPoolNonSequencedExample();
148  ThreadPoolSequencedExample();
149  ThreadPoolSingleThreadExample();
150
151  LOG(INFO) << "Example finished in " << timer.Elapsed().InMillisecondsF()
152            << "ms";
153  TRACE_EVENT_FLUSH_TO_STREAM(LOG(INFO) << "Trace:\n");
154
155  base::Deinitialize();
156  return 0;
157}