From e5451f72756b49550300a35c30947f4fc41473da Mon Sep 17 00:00:00 2001 From: PtCu <1365699009@qq.com> Date: Sun, 6 Feb 2022 02:23:59 +0800 Subject: [PATCH] finish --- .gitignore | 1 + MTQueue.h | 77 ++++++++++++++++++++++++++------------------ ThreadPool.h | 49 ++++++++++++++++++++++++++++ main.cpp | 91 +++++++++++++++++++++++++++++----------------------- 4 files changed, 146 insertions(+), 72 deletions(-) create mode 100644 ThreadPool.h diff --git a/.gitignore b/.gitignore index 9ed92a0..5fa30d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build GNUmakefile +.vscode/ \ No newline at end of file diff --git a/MTQueue.h b/MTQueue.h index 38d2eee..e46be86 100644 --- a/MTQueue.h +++ b/MTQueue.h @@ -5,67 +5,80 @@ #include template -class MTQueue { +class MTQueue +{ std::condition_variable m_cv; - std::mutex m_mtx; + mutable std::mutex m_mtx; std::vector m_arr; public: - T pop() { + bool empty() const + { std::unique_lock lck(m_mtx); - m_cv.wait(lck, [this] { return !m_arr.empty(); }); + return m_arr.empty(); + } + + T pop() + { + std::unique_lock lck(m_mtx); + m_cv.wait(lck, [this] + { return !m_arr.empty(); }); T ret = std::move(m_arr.back()); m_arr.pop_back(); return ret; } - auto pop_hold() { + auto pop_hold() + { std::unique_lock lck(m_mtx); - m_cv.wait(lck, [this] { return !m_arr.empty(); }); + m_cv.wait(lck, [this] + { return !m_arr.empty(); }); T ret = std::move(m_arr.back()); m_arr.pop_back(); return std::pair(std::move(ret), std::move(lck)); } - void push(T val) { + void push(T val) + { std::unique_lock lck(m_mtx); m_arr.push_back(std::move(val)); m_cv.notify_one(); } - void push_many(std::initializer_list vals) { + void push_many(std::initializer_list vals) + { std::unique_lock lck(m_mtx); std::copy( - std::move_iterator(vals.begin()), - std::move_iterator(vals.end()), - std::back_insert_iterator(m_arr)); + std::move_iterator(vals.begin()), + std::move_iterator(vals.end()), + std::back_insert_iterator(m_arr)); m_cv.notify_all(); } }; -int main() { - MTQueue foods; +// int main() { +// MTQueue foods; - std::thread t1([&] { - for (int i = 0; i < 2; i++) { - auto food = foods.pop(); - std::cout << "t1 got food:" << food << std::endl; - } - }); +// std::thread t1([&] { +// for (int i = 0; i < 2; i++) { +// auto food = foods.pop(); +// std::cout << "t1 got food:" << food << std::endl; +// } +// }); - std::thread t2([&] { - for (int i = 0; i < 2; i++) { - auto food = foods.pop(); - std::cout << "t2 got food:" << food << std::endl; - } - }); +// std::thread t2([&] { +// for (int i = 0; i < 2; i++) { +// auto food = foods.pop(); +// std::cout << "t2 got food:" << food << std::endl; +// } +// }); - foods.push(42); - foods.push(233); - foods.push_many({666, 4399}); +// foods.push(42); +// foods.push(233); +// foods.push_many({666, 4399}); - t1.join(); - t2.join(); +// t1.join(); +// t2.join(); - return 0; -} +// return 0; +// } diff --git a/ThreadPool.h b/ThreadPool.h new file mode 100644 index 0000000..f916171 --- /dev/null +++ b/ThreadPool.h @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include "MTQueue.h" +#include +class ThreadPool +{ +public: + explicit ThreadPool(size_t num) + : _threads_num(num), _stopped(false) + { + for (size_t i = 0; i < _threads_num; ++i) + { + _pool.emplace_back([this]() + { + for (;;) + { + if (_stopped && _task_queue.empty()) + return; + auto task = _task_queue.pop(); + task(); + } + }); + } + } + void create(std::function start) + { + // 作业要求3:如何让这个线程保持在后台执行不要退出? + // 提示:改成 async 和 future 且用法正确也可以加分 + _task_queue.push(start); + } + ~ThreadPool() + { + _stopped = true; + for (auto &th : _pool) + { + th.join(); + } + + } + +private: + std::atomic_bool _stopped; + size_t _threads_num; + std::vector _pool; + MTQueue> _task_queue; +}; + diff --git a/main.cpp b/main.cpp index f4ecab8..d44abb1 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,4 @@ -// 小彭老师作业05:假装是多线程 HTTP 服务器 - 富连网大厂面试官觉得很赞 +// 小彭老师作业05:假装是多线程 HTTP 服务器 - 富连网大厂面试官觉得很赞 #include #include #include @@ -6,20 +6,25 @@ #include #include #include - - -struct User { +#include +#include +#include "ThreadPool.h" +struct User +{ std::string password; std::string school; std::string phone; }; std::map users; -std::map has_login; // 换成 std::chrono::seconds 之类的 - +std::map has_login; // 换成 std::chrono::seconds 之类的 +std::shared_mutex users_mtx; +std::shared_mutex login_mtx; // 作业要求1:把这些函数变成多线程安全的 // 提示:能正确利用 shared_mutex 加分,用 lock_guard 系列加分 -std::string do_register(std::string username, std::string password, std::string school, std::string phone) { +std::string do_register(const std::string& username, const std::string &password,const std::string& school, const std::string& phone) +{ + std::unique_lock grd(users_mtx); User user = {password, school, phone}; if (users.emplace(username, user).second) return "注册成功"; @@ -27,15 +32,21 @@ std::string do_register(std::string username, std::string password, std::string return "用户名已被注册"; } -std::string do_login(std::string username, std::string password) { +std::string do_login(const std::string &username, const std::string &password) +{ // 作业要求2:把这个登录计时器改成基于 chrono 的 - long now = time(NULL); // C 语言当前时间 - if (has_login.find(username) != has_login.end()) { - int sec = now - has_login.at(username); // C 语言算时间差 - return std::to_string(sec) + "秒内登录过"; + + std::unique_lock unique_grd(login_mtx); + auto now = std::chrono::steady_clock::now(); + if (has_login.find(username) != has_login.end()) + { + auto sec = now - has_login.at(username); // C 语言算时间差 + return std::to_string(std::chrono::duration_cast(sec).count()) + "秒内登录过"; } has_login[username] = now; + unique_grd.unlock(); + std::shared_lock shard_grd(users_mtx); if (users.find(username) == users.end()) return "用户名错误"; if (users.at(username).password != password) @@ -43,7 +54,13 @@ std::string do_login(std::string username, std::string password) { return "登录成功"; } -std::string do_queryuser(std::string username) { +std::string do_queryuser(const std::string &username) +{ + std::shared_lock grd(users_mtx); + if (users.find(username) == users.end()){ + return "用户不存在"; + } + auto &user = users.at(username); std::stringstream ss; ss << "用户名: " << username << std::endl; @@ -53,37 +70,31 @@ std::string do_queryuser(std::string username) { } -struct ThreadPool { - void create(std::function start) { - // 作业要求3:如何让这个线程保持在后台执行不要退出? - // 提示:改成 async 和 future 且用法正确也可以加分 - std::thread thr(start); - } -}; +namespace test +{ // 测试用例?出水用力! + std::string username[] = {"张心欣", "王鑫磊", "彭于斌", "胡原名"}; + std::string password[] = {"hellojob", "anti-job42", "cihou233", "reCihou_!"}; + std::string school[] = {"九百八十五大鞋", "浙江大鞋", "剑桥大鞋", "麻绳理工鞋院"}; + std::string phone[] = {"110", "119", "120", "12315"}; +} -ThreadPool tpool; +ThreadPool tpool(std::thread::hardware_concurrency()); +int main() +{ + constexpr int n = 262144; -namespace test { // 测试用例?出水用力! -std::string username[] = {"张心欣", "王鑫磊", "彭于斌", "胡原名"}; -std::string password[] = {"hellojob", "anti-job42", "cihou233", "reCihou_!"}; -std::string school[] = {"九百八十五大鞋", "浙江大鞋", "剑桥大鞋", "麻绳理工鞋院"}; -std::string phone[] = {"110", "119", "120", "12315"}; -} - -int main() { - for (int i = 0; i < 262144; i++) { - tpool.create([&] { - std::cout << do_register(test::username[rand() % 4], test::password[rand() % 4], test::school[rand() % 4], test::phone[rand() % 4]) << std::endl; - }); - tpool.create([&] { - std::cout << do_login(test::username[rand() % 4], test::password[rand() % 4]) << std::endl; - }); - tpool.create([&] { - std::cout << do_queryuser(test::username[rand() % 4]) << std::endl; - }); + for (int i = 0; i