1 /* 2 * Copyright (c) 2021 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 DFSU_THREAD_H 16 #define DFSU_THREAD_H 17 18 #include <atomic> 19 #include <condition_variable> 20 #include <functional> 21 #include <mutex> 22 #include <thread> 23 #include "utils_log.h" 24 25 namespace OHOS { 26 namespace Storage { 27 namespace DistributedFile { 28 namespace Utils { 29 class DfsuThread { 30 public: 31 DfsuThread() = default; 32 DfsuThread(const DfsuThread &) = delete; 33 DfsuThread &operator=(const DfsuThread &) = delete; 34 ~DfsuThread()35 ~DfsuThread() 36 { 37 Stop(); 38 } 39 40 template<class Fn, class... Args> Run(Fn && Fx,Args &&...Ax)41 bool Run(Fn &&Fx, Args &&...Ax) 42 { 43 std::unique_lock<std::mutex> lock(threadMutex_); 44 if (thread_ != nullptr) { 45 return false; 46 } 47 running_ = true; 48 thread_ = std::make_unique<std::thread>(std::forward<Fn>(Fx), std::forward<Args>(Ax)...); 49 return true; 50 } 51 52 bool RunLoop(std::function<bool()> task, uint64_t interval, uint32_t retryTimes = UINT32_MAX) 53 { 54 std::unique_lock<std::mutex> lock(threadMutex_); 55 if (thread_ != nullptr) { 56 return false; 57 } 58 running_ = true; 59 thread_ = std::make_unique<std::thread>([this, task, interval, retryTimes] { 60 uint32_t times = retryTimes; 61 LOGD("DfsThread: entering loop"); 62 while ((!task()) && (times > 0)) { 63 times--; 64 std::unique_lock<std::mutex> lock(sleepMutex_); 65 bool stop = 66 sleepCv_.wait_for(lock, std::chrono::milliseconds(interval), [this]() { return !this->running_; }); 67 if (stop) { // is stopped 68 break; 69 } 70 } 71 LOGD("DfsThread: leaving loop"); 72 }); 73 return true; 74 } 75 76 bool RunLoopFlexible(std::function<bool(uint64_t &)> task, uint64_t interval, uint32_t retryTimes = UINT32_MAX) 77 { 78 std::unique_lock<std::mutex> lock(threadMutex_); 79 if (thread_ != nullptr) { 80 return false; 81 } 82 running_ = true; 83 thread_ = std::make_unique<std::thread>([this, task, interval, retryTimes] { 84 uint32_t times = retryTimes; 85 uint64_t duration = interval; 86 LOGD("DfsThread: entering flexible loop"); 87 while ((!task(duration)) && (times > 0)) { 88 times--; 89 std::unique_lock<std::mutex> lock(sleepMutex_); 90 bool stop = 91 sleepCv_.wait_for(lock, std::chrono::milliseconds(duration), [this]() { return !this->running_; }); 92 if (stop) { // is stopped 93 break; 94 } 95 } 96 LOGD("DfsThread: leaving flexible loop"); 97 }); 98 return true; 99 } 100 Stop()101 bool Stop() 102 { 103 std::unique_lock<std::mutex> lockThread(threadMutex_); 104 if (thread_ == nullptr) { 105 return true; 106 } 107 { 108 std::unique_lock<std::mutex> lockSleep(sleepMutex_); 109 running_ = false; 110 sleepCv_.notify_one(); 111 } 112 LOGD("wait thread to stop"); 113 if (thread_->joinable()) { 114 thread_->join(); 115 } 116 thread_ = nullptr; 117 return true; 118 } 119 120 bool operator==(std::thread::id id) 121 { 122 if (thread_ == nullptr) { 123 return false; 124 } 125 return thread_->get_id() == id; 126 } 127 128 private: 129 std::atomic_bool running_ {false}; 130 std::mutex threadMutex_ {}; 131 std::unique_ptr<std::thread> thread_ {nullptr}; 132 std::mutex sleepMutex_ {}; 133 std::condition_variable sleepCv_ {}; 134 }; 135 } // namespace Utils 136 } // namespace DistributedFile 137 } // namespace Storage 138 } // namespace OHOS 139 #endif // DFSU_THREAD_H