diff --git a/main.cpp b/main.cpp index f4ecab8..708799f 100644 --- a/main.cpp +++ b/main.cpp @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include struct User { @@ -15,11 +19,18 @@ struct User { }; std::map users; -std::map has_login; // 换成 std::chrono::seconds 之类的 +// std::map has_login; // 换成 std::chrono::seconds 之类的 + +std::map has_login; +std::shared_mutex user_mutex; +std::shared_mutex login_mutex; + + // 作业要求1:把这些函数变成多线程安全的 // 提示:能正确利用 shared_mutex 加分,用 lock_guard 系列加分 std::string do_register(std::string username, std::string password, std::string school, std::string phone) { + std::unique_lock lock(user_mutex); User user = {password, school, phone}; if (users.emplace(username, user).second) return "注册成功"; @@ -27,15 +38,28 @@ std::string do_register(std::string username, std::string password, std::string return "用户名已被注册"; } +using double_ms = std::chrono::duration; std::string do_login(std::string username, 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 lock(login_mutex); // ensure has_login[username] = t1 without data race + auto t1 = std::chrono::steady_clock::now(); + if (has_login.find(username) != has_login.end()) { + auto diff = t1 - has_login[username]; + double msec = std::chrono::duration_cast(diff).count(); + return std::to_string(msec) + "ms内登录过"; + } + has_login[username] = t1; } - has_login[username] = now; - + // has_login[username] = now; + // { + // std::unique_lock lock(login_mutex); + + // } + + std::shared_lock lock(user_mutex); // shared_lock确保.find的时候没有write if (users.find(username) == users.end()) return "用户名错误"; if (users.at(username).password != password) @@ -44,6 +68,8 @@ std::string do_login(std::string username, std::string password) { } std::string do_queryuser(std::string username) { + std::shared_lock lock(user_mutex); + if (users.find(username) == users.end()) return "user name does not exist"; auto &user = users.at(username); std::stringstream ss; ss << "用户名: " << username << std::endl; @@ -54,13 +80,41 @@ std::string do_queryuser(std::string username) { struct ThreadPool { + std::vector> futures; void create(std::function start) { // 作业要求3:如何让这个线程保持在后台执行不要退出? // 提示:改成 async 和 future 且用法正确也可以加分 - std::thread thr(start); + // not sure if to std::launch::aynsc here, too many threads might get it stuck + // std::async(function) will return a future element + futures.emplace_back(std::async(start)); + } + void waitForAll() { + for (auto &f : futures) { + f.get(); // wait for all to happen + } } }; +// 下面这样写应该也可以, +// struct ThreadPool { +// // 动态管理vector大小,自动destruct +// std::unique_ptr> threads; + +// ThreadPool() : threads(std::make_unique>()) {} + +// void create(std::function start) { +// threads->emplace_back(std::thread(start)); +// } + +// void waitForAll() { +// for (auto &t : *threads) { +// if (t.joinable()) { +// t.join(); // 等待所有线程完成 +// } +// } +// } +// }; + ThreadPool tpool; @@ -73,17 +127,23 @@ std::string phone[] = {"110", "119", "120", "12315"}; int main() { for (int i = 0; i < 262144; i++) { + // call register tpool.create([&] { std::cout << do_register(test::username[rand() % 4], test::password[rand() % 4], test::school[rand() % 4], test::phone[rand() % 4]) << std::endl; }); + + // call login tpool.create([&] { std::cout << do_login(test::username[rand() % 4], test::password[rand() % 4]) << std::endl; }); + + // user might be queried to wait tpool.create([&] { std::cout << do_queryuser(test::username[rand() % 4]) << std::endl; }); } // 作业要求4:等待 tpool 中所有线程都结束后再退出 + tpool.waitForAll(); return 0; -} +} \ No newline at end of file