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.
#include <thread>
#include "base/bind.h"
#include "base/callback.h"
#include "base/init.h"
#include "base/logging.h"
#include "base/synchronization/auto_signaller.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "base/threading/thread_pool.h"
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_flow.h"
#include "base/trace_event/trace_flush.h"
namespace {
std::shared_ptr<base::SequencedTaskRunner> tr1;
std::shared_ptr<base::SequencedTaskRunner> tr2;
} // namespace
void Task1(std::shared_ptr<base::TaskRunner> current,
std::shared_ptr<base::TaskRunner> next,
base::WaitableEvent* five_left_event,
base::AutoSignaller finished_event,
int n) {
CHECK_GE(n, 0) << "`n` must be greater or equal to 0";
TRACE_EVENT("thread_example", "task1", "n", std::to_string(n));
TRACE_EVENT_WITH_FLOW_STEP("thread_example", "flow:ThreadExample", &tr1);
LOG(INFO) << __FUNCTION__ << "() Writing from thread "
<< std::this_thread::get_id() << " with n=" << n
<< "(tr1: " << tr1->RunsTasksInCurrentSequence()
<< ", tr2: " << tr2->RunsTasksInCurrentSequence() << ")"
<< std::endl;
if (n == 5) {
five_left_event->Signal();
}
if (n > 0) {
next->PostTask(FROM_HERE,
base::BindOnce(&Task1, next, current, five_left_event,
std::move(finished_event), n - 1));
}
}
void ThreadExample() {
TRACE_EVENT("thread_example", "ThreadExample");
base::Thread t1{};
base::Thread t2{};
t1.Start();
t2.Start();
tr1 = t1.TaskRunner();
tr2 = t2.TaskRunner();
base::WaitableEvent five_left_event{};
base::WaitableEvent finished_event{};
{
TRACE_EVENT("thread_example", "Async work start");
TRACE_EVENT_WITH_FLOW_BEGIN("thread_example", "flow:ThreadExample", &tr1);
tr1->PostTask(FROM_HERE,
base::BindOnce(&Task1, tr1, tr2, &five_left_event,
base::AutoSignaller{&finished_event}, 10));
}
five_left_event.Wait();
LOG(INFO) << __FUNCTION__ << "() (at most 5 calls left)...";
finished_event.Wait();
LOG(INFO) << __FUNCTION__ << "() finished";
{
TRACE_EVENT_WITH_FLOW_END("thread_example", "flow:ThreadExample", &tr1);
TRACE_EVENT("thread_example", "Async work done");
}
t2.Stop();
t1.Stop();
}
void ThreadDelayedExample() {
base::Thread thread{};
base::WaitableEvent finished_event{};
thread.Start();
thread.TaskRunner()->PostDelayedTask(
FROM_HERE,
base::BindOnce(
[]([[maybe_unused]] base::AutoSignaller finished_signaller) {
LOG(INFO)
<< "ThreadDelayedExample() delayed (300ms) task executing";
},
base::AutoSignaller{&finished_event}),
base::Milliseconds(300));
thread.TaskRunner()->PostTask(
FROM_HERE, base::BindOnce([]() {
LOG(INFO) << "ThreadDelayedExample() non-delayed task executing";
}));
thread.TaskRunner()->PostDelayedTask(
FROM_HERE, base::BindOnce([]() {
LOG(INFO) << "ThreadDelayedExample() delayed (100ms) task executing";
}),
base::Milliseconds(100));
finished_event.Wait();
LOG(INFO) << __FUNCTION__ << "() finished";
thread.Stop();
}
void ThreadPoolNonSequencedExample() {
base::ThreadPool pool{1};
pool.Start();
auto generic_tr1 = pool.GetTaskRunner();
pool.Stop();
}
void ThreadPoolSequencedExample() {
base::ThreadPool pool{4};
pool.Start();
auto sequenced_tr1 = pool.CreateSequencedTaskRunner();
auto sequenced_tr2 = pool.CreateSequencedTaskRunner();
pool.Stop();
}
void ThreadPoolSingleThreadExample() {
base::ThreadPool pool{4};
pool.Start();
auto single_thread_tr1 = pool.CreateSingleThreadTaskRunner();
pool.Stop();
}
int main(int argc, char* argv[]) {
base::Initialize(argc, argv);
const auto timer = base::ElapsedTimer{};
ThreadExample();
ThreadDelayedExample();
ThreadPoolNonSequencedExample();
ThreadPoolSequencedExample();
ThreadPoolSingleThreadExample();
LOG(INFO) << "Example finished in " << timer.Elapsed().InMillisecondsF()
<< "ms";
TRACE_EVENT_FLUSH_TO_STREAM(LOG(INFO) << "Trace:\n");
base::Deinitialize();
return 0;
}