1 /* 2 * Copyright (c) 2025 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 #ifndef AUDIO_TASK_LOOP_H 16 #define AUDIO_TASK_LOOP_H 17 18 #include <atomic> 19 #include <thread> 20 #include <functional> 21 #include <condition_variable> 22 #include <memory> 23 #include <mutex> 24 #include <string> 25 #include <string_view> 26 #include <queue> 27 namespace OHOS { 28 namespace AudioStandard { 29 class AudioTaskLoop { 30 public: 31 friend class AudioLoopThread; 32 33 AudioTaskLoop() = default; 34 35 ~AudioTaskLoop() = default; 36 37 AudioTaskLoop(const AudioTaskLoop&) = delete; 38 AudioTaskLoop(AudioTaskLoop&&) = delete; 39 AudioTaskLoop& operator=(const AudioTaskLoop&) = delete; 40 AudioTaskLoop& operator=(AudioTaskLoop&&) = delete; 41 AsyncExit()42 void AsyncExit() 43 { 44 std::lock_guard lock(mutex_); 45 isExited_ = true; 46 cV_.notify_all(); 47 } 48 PostTask(const std::function<void ()> & task)49 void PostTask(const std::function<void()> &task) 50 { 51 std::lock_guard lock(mutex_); 52 tasks_.push(task); 53 cV_.notify_all(); 54 } 55 PostTask(std::function<void ()> && task)56 void PostTask(std::function<void()> &&task) 57 { 58 std::lock_guard lock(mutex_); 59 tasks_.push(std::move(task)); 60 cV_.notify_all(); 61 } 62 private: Wait()63 void Wait() 64 { 65 std::unique_lock lock(mutex_); 66 cV_.wait(lock, [this] () { 67 return (isExited_ || !tasks_.empty()); 68 }); 69 } 70 ProcessTasks(std::queue<std::function<void ()>> & tasks)71 static void ProcessTasks(std::queue<std::function<void()>> &tasks) 72 { 73 while (!tasks.empty()) { 74 auto &&task = tasks.front(); 75 if (task) { 76 task(); 77 } 78 tasks.pop(); 79 } 80 } 81 ProcessTasks()82 void ProcessTasks() 83 { 84 std::queue<std::function<void()>> tasks; 85 { 86 std::lock_guard lock(mutex_); 87 tasks.swap(tasks_); 88 } 89 ProcessTasks(tasks); 90 } 91 Loop()92 void Loop() 93 { 94 while (true) { 95 Wait(); 96 ProcessTasks(); 97 98 std::lock_guard lock(mutex_); 99 if (isExited_ && tasks_.empty()) { return; } 100 } 101 } 102 103 std::queue<std::function<void()>> tasks_; 104 std::mutex mutex_; 105 std::condition_variable cV_; 106 bool isExited_ = false; 107 }; 108 109 class AudioLoopThread { 110 public: AudioLoopThread(const std::string & threadName)111 AudioLoopThread(const std::string &threadName) 112 { 113 if (loop_ != nullptr) { 114 auto strongRef = loop_; 115 std::thread loopThread([strongRef] () { 116 strongRef->Loop(); 117 }); 118 pthread_setname_np(loopThread.native_handle(), threadName.c_str()); 119 loopThread.detach(); 120 } 121 } 122 123 AudioLoopThread(const AudioLoopThread&) = delete; 124 AudioLoopThread(AudioLoopThread&&) = delete; 125 AudioLoopThread& operator=(const AudioLoopThread&) = delete; 126 AudioLoopThread& operator=(AudioLoopThread&&) = delete; 127 PostTask(const std::function<void ()> & task)128 void PostTask(const std::function<void()> &task) 129 { 130 if (loop_ != nullptr) { 131 loop_->PostTask(task); 132 } 133 } 134 PostTask(std::function<void ()> && task)135 void PostTask(std::function<void()> &&task) 136 { 137 if (loop_ != nullptr) { 138 loop_->PostTask(std::move(task)); 139 } 140 } 141 ~AudioLoopThread()142 ~AudioLoopThread() 143 { 144 if (loop_ != nullptr) { 145 loop_->AsyncExit(); 146 } 147 } 148 149 private: 150 std::shared_ptr<AudioTaskLoop> loop_ = std::make_shared<AudioTaskLoop>(); 151 }; 152 } // namespace AudioStandard 153 } // namespace OHOS 154 #endif 155