1 /*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "medialibrary_async_worker.h"
17
18 #include <pthread.h>
19 #include "media_log.h"
20
21 using namespace std;
22
23 namespace OHOS {
24 namespace Media {
25 static const int32_t SUCCESS = 0;
26 static const int32_t BG_SLEEP_COUNT = 500;
27 static const int32_t FG_SLEEP_COUNT = 50;
28 static const int32_t REST_FOR_MILLISECOND = 20;
29 static const int32_t REST_FOR_LONG_SECOND = 2;
30 static const int32_t THREAD_NUM = 2;
31 shared_ptr<MediaLibraryAsyncWorker> MediaLibraryAsyncWorker::asyncWorkerInstance_{nullptr};
32 mutex MediaLibraryAsyncWorker::instanceLock_;
33
GetInstance()34 shared_ptr<MediaLibraryAsyncWorker> MediaLibraryAsyncWorker::GetInstance()
35 {
36 if (asyncWorkerInstance_ == nullptr) {
37 lock_guard<mutex> lockGuard(instanceLock_);
38 asyncWorkerInstance_ = shared_ptr<MediaLibraryAsyncWorker>(new MediaLibraryAsyncWorker());
39 if (asyncWorkerInstance_ != nullptr) {
40 asyncWorkerInstance_->Init();
41 }
42 }
43 return asyncWorkerInstance_;
44 }
45
MediaLibraryAsyncWorker()46 MediaLibraryAsyncWorker::MediaLibraryAsyncWorker() : isThreadRunning_(false), doneTotal_(0)
47 {}
48
~MediaLibraryAsyncWorker()49 MediaLibraryAsyncWorker::~MediaLibraryAsyncWorker()
50 {
51 isThreadRunning_ = false;
52 bgWorkCv_.notify_all();
53 for (auto &thread : threads_) {
54 if (thread.joinable()) {
55 thread.join();
56 }
57 }
58 asyncWorkerInstance_ = nullptr;
59 }
60
Init()61 void MediaLibraryAsyncWorker::Init()
62 {
63 isThreadRunning_ = true;
64 doneTotal_ = 0;
65 for (auto i = 0; i < THREAD_NUM; i++) {
66 threads_.emplace_back(bind(&MediaLibraryAsyncWorker::StartWorker, this, i));
67 }
68 }
69
Interrupt()70 void MediaLibraryAsyncWorker::Interrupt()
71 {
72 ReleaseBgTask();
73 }
74
Stop()75 void MediaLibraryAsyncWorker::Stop()
76 {
77 ReleaseBgTask();
78 ReleaseFgTask();
79 }
80
AddTask(const shared_ptr<MediaLibraryAsyncTask> & task,bool isFg)81 int32_t MediaLibraryAsyncWorker::AddTask(const shared_ptr<MediaLibraryAsyncTask> &task, bool isFg)
82 {
83 if (isFg) {
84 lock_guard<mutex> lockGuard(fgTaskLock_);
85 fgTaskQueue_.push(task);
86 } else {
87 lock_guard<mutex> lockGuard(bgTaskLock_);
88 bgTaskQueue_.push(task);
89 }
90
91 bgWorkCv_.notify_one();
92 return SUCCESS;
93 }
94
GetFgTask()95 shared_ptr<MediaLibraryAsyncTask> MediaLibraryAsyncWorker::GetFgTask()
96 {
97 lock_guard<mutex> lockGuard(fgTaskLock_);
98 if (fgTaskQueue_.empty()) {
99 return nullptr;
100 }
101 shared_ptr<MediaLibraryAsyncTask> task = fgTaskQueue_.front();
102 fgTaskQueue_.pop();
103 return task;
104 }
105
ReleaseFgTask()106 void MediaLibraryAsyncWorker::ReleaseFgTask()
107 {
108 lock_guard<mutex> lockGuard(fgTaskLock_);
109 std::queue<std::shared_ptr<MediaLibraryAsyncTask>> tmp;
110 fgTaskQueue_.swap(tmp);
111 }
112
GetBgTask()113 shared_ptr<MediaLibraryAsyncTask> MediaLibraryAsyncWorker::GetBgTask()
114 {
115 lock_guard<mutex> lockGuard(bgTaskLock_);
116 if (bgTaskQueue_.empty()) {
117 return nullptr;
118 }
119 shared_ptr<MediaLibraryAsyncTask> task = bgTaskQueue_.front();
120 bgTaskQueue_.pop();
121 return task;
122 }
123
ReleaseBgTask()124 void MediaLibraryAsyncWorker::ReleaseBgTask()
125 {
126 lock_guard<mutex> lockGuard(bgTaskLock_);
127 std::queue<std::shared_ptr<MediaLibraryAsyncTask>> tmp;
128 bgTaskQueue_.swap(tmp);
129 }
130
IsFgQueueEmpty()131 bool MediaLibraryAsyncWorker::IsFgQueueEmpty()
132 {
133 lock_guard<mutex> lock_Guard(fgTaskLock_);
134 return fgTaskQueue_.empty();
135 }
136
IsBgQueueEmpty()137 bool MediaLibraryAsyncWorker::IsBgQueueEmpty()
138 {
139 lock_guard<mutex> lock_Guard(bgTaskLock_);
140 return bgTaskQueue_.empty();
141 }
142
WaitForTask()143 void MediaLibraryAsyncWorker::WaitForTask()
144 {
145 std::unique_lock<std::mutex> lock(bgWorkLock_);
146 bgWorkCv_.wait(lock,
147 [this]() { return !isThreadRunning_ || !IsFgQueueEmpty() || !IsBgQueueEmpty(); });
148 }
149
SleepFgWork()150 void MediaLibraryAsyncWorker::SleepFgWork()
151 {
152 if ((doneTotal_.load() % FG_SLEEP_COUNT) == 0) {
153 this_thread::sleep_for(chrono::milliseconds(REST_FOR_MILLISECOND));
154 }
155 }
156
SleepBgWork()157 void MediaLibraryAsyncWorker::SleepBgWork()
158 {
159 this_thread::sleep_for(chrono::milliseconds(REST_FOR_MILLISECOND));
160 if ((doneTotal_.load() % BG_SLEEP_COUNT) == 0) {
161 this_thread::sleep_for(chrono::seconds(REST_FOR_LONG_SECOND));
162 }
163 }
164
StartWorker(int num)165 void MediaLibraryAsyncWorker::StartWorker(int num)
166 {
167 string name("MediaLibraryAsyncWorker");
168 name.append(to_string(num));
169 pthread_setname_np(pthread_self(), name.c_str());
170 while (true) {
171 WaitForTask();
172 if (!isThreadRunning_) {
173 return;
174 }
175 if (!IsFgQueueEmpty()) {
176 shared_ptr<MediaLibraryAsyncTask> fgTask = GetFgTask();
177 if (fgTask != nullptr) {
178 fgTask->executor_(fgTask->data_);
179 fgTask = nullptr;
180 doneTotal_++;
181 SleepFgWork();
182 }
183 } else if (!IsBgQueueEmpty()) {
184 shared_ptr<MediaLibraryAsyncTask> bgTask = GetBgTask();
185 if (bgTask != nullptr) {
186 bgTask->executor_(bgTask->data_);
187 bgTask = nullptr;
188 doneTotal_++;
189 SleepBgWork();
190 }
191 }
192 }
193 }
194 } // namespace Media
195 } // namespace OHOS
196