diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..06caa9d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "map": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..bb108c6 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++.exe 生成活动文件", + "command": "C:\\Program Files (x86)\\mingw64\\bin\\g++.exe", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}\\${fileBasenameNoExtension}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "调试器生成的任务。" + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/main.cpp b/main.cpp index f4ecab8..64631d3 100644 --- a/main.cpp +++ b/main.cpp @@ -6,20 +6,35 @@ #include #include #include +#include +#include +#include +#define __Change__ //用于标记 时间标签的使用方式,定义这个宏定义则使用std::chrono,否则使用 time +//#define __for_test__ //用于标记 测试函数,定义这个宏定义 则使用有返回值的std::async, 否则没有返回值 struct User { std::string password; std::string school; std::string phone; -}; +};//用户信息 + +std::map users;//<用户名,用户信息> + +#ifdef __Change__ +std::map has_login;//<用户名,登录时刻> +#endif -std::map users; +#ifndef __Change__ std::map has_login; // 换成 std::chrono::seconds 之类的 +#endif // 作业要求1:把这些函数变成多线程安全的 // 提示:能正确利用 shared_mutex 加分,用 lock_guard 系列加分 +///对三个函数使用三个互斥锁来进行线程保护 +std::mutex mtx0,mtx1,mtx2; std::string do_register(std::string username, std::string password, std::string school, std::string phone) { + std::lock_guard lockgrd(mtx0); User user = {password, school, phone}; if (users.emplace(username, user).second) return "注册成功"; @@ -28,62 +43,224 @@ std::string do_register(std::string username, std::string password, std::string } 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) + "秒内登录过"; - } - has_login[username] = now; + std::lock_guard lockgrd(mtx1); + #ifdef __Change__ + //std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); // C 语言当前时间 + auto now = std::chrono::steady_clock::now(); // C 语言当前时间 + auto duration = now.time_since_epoch(); + auto seconds = std::chrono::duration_cast(duration); + #endif + + #ifndef __Change__ + // 作业要求2:把这个登录计时器改成基于 chrono 的' + long now = time(NULL); + #endif + + if (has_login.find(username) != has_login.end()) {//用户已经登录 + #ifdef __Change__ + auto sec = seconds - has_login.at(username);// C 语言算时间差 + return std::to_string(sec.count()) + "秒内登录过"; + #endif - if (users.find(username) == users.end()) + #ifndef __Change__ + int sec = now - has_login.at(username); // C 语言算时间差 + return std::to_string(sec) + "秒内登录过"; + #endif + + } + if (users.find(username) == users.end())//用户没有注册 return "用户名错误"; - if (users.at(username).password != password) + if (users.at(username).password != password)//用户登录密码错误 return "密码错误"; + #ifdef __Change__ + has_login[username] = seconds;//用户登录成功 添加到 has_login 中 + #endif + + #ifndef __Change__ + has_login[username] = now;//新用户登录成功 添加到 has_login 中 + #endif + return "登录成功"; } -std::string do_queryuser(std::string username) { +std::string do_queryuser(std::string username) {//返回用户的用户信息 + std::lock_guard lockgrd(mtx2); auto &user = users.at(username); std::stringstream ss; + //将字符串流插入到ss ss << "用户名: " << username << std::endl; ss << "学校:" << user.school << std::endl; ss << "电话: " << user.phone << std::endl; - return ss.str(); + return ss.str();//返回字符串流 } +#ifdef __for_test__ +std::vector> A;//用于保存将子线程的返回对象future +#endif struct ThreadPool { +#ifdef __for_test__ +///用于test2 test1 + void create(std::function start) { + // 作业要求3:如何让这个线程保持在后台执行不要退出? + // 提示:改成 async 和 future 且用法正确也可以加分 + //std::thread thr(start); + A.push_back(std::async(std::launch::async,start));; + } +#endif + +#ifndef __for_test__ +///用于test0 void create(std::function start) { // 作业要求3:如何让这个线程保持在后台执行不要退出? // 提示:改成 async 和 future 且用法正确也可以加分 - std::thread thr(start); + //std::thread thr(start); + std::async(std::launch::async,start); } +#endif }; ThreadPool tpool; - namespace test { // 测试用例?出水用力! -std::string username[] = {"张心欣", "王鑫磊", "彭于斌", "胡原名"}; -std::string password[] = {"hellojob", "anti-job42", "cihou233", "reCihou_!"}; -std::string school[] = {"九百八十五大鞋", "浙江大鞋", "剑桥大鞋", "麻绳理工鞋院"}; -std::string phone[] = {"110", "119", "120", "12315"}; +std::string username[] = {"张心欣", "王鑫磊", "彭于斌", "胡原名","曾睿"}; +std::string password[] = {"hellojob", "anti-job42", "cihou233", "reCihou_!","123456789"}; +std::string school[] = {"九百八十五大鞋", "浙江大鞋", "剑桥大鞋", "麻绳理工鞋院","西电"}; +std::string phone[] = {"110", "119", "120", "12315","199"}; +} + +#ifdef __for_test__ +#ifdef __Change__ +int test2(){//test2:手动对test测试用例 do_register do_login do_queryuser + std::string str; + std::cout<< "调用线程池进行用户注册。" << std::endl; + for(int i=0;i<5;i++) { + ///这里需要按值传递 否则会导致在lambda表达式运行过程中 引用传递的值发生来改变 + ///lambda 返回的 std::string 通过async异步操作 返回到future中 + tpool.create([i] -> std::string { + /// 这里即使不加return 也不会报错 + do_register(test::username[i], test::password[i], test::school[i], test::phone[i]);//用户注册 + //return + } + ); + } + ///通过sleep的方式来等待future就绪(进程执行结束)并不是很安全 + std::cout<< "等待5s-->子线程完成:打印注册信息" << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(5));//等待A中的future就绪 + int i=0; + for(auto it = users.begin(); it != users.end(); ++it){ + //迭代users 并打印注册信息 + ///每个future对象只能调用一次get + std::cout << it->first << ' ' << A[i++].get() << std::endl; + } + A.clear(); + std::cout<< "调用线程池对已经注册的用户,进行登录。" << std::endl; + for(auto it = users.begin(); it!= users.end();++it){ + tpool.create( + [it]->std::string { + ///这里lambda表达式有返回值 则一定要有return 否则会导致后面的打印出现错误 + /// 即使不打印 也会报错 munmap_chunk(): invalid pointer + return do_login(it->first,it->second.password);//return + } + ); + std::this_thread::sleep_for(std::chrono::seconds(1));//设置每次登录间隔1s + } + ///通过sleep的方式来等待future就绪(进程执行结束)并不是很安全 + std::cout<< "等待10s-->子线程完成:打印登录信息" << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(10));//等待A中的future就绪 + i=0; + for(auto it = has_login.begin(); it != has_login.end(); ++it){ + //迭代has_login 并打印登录信息 + /// munmap_chunk(): invalid pointer + std::cout << it->first << ' ' << it->second.count() << ' ' << A[i++].get() << std::endl;//每个future对象只能调用一次get + } + A.clear(); + std::cout<< "调用线程池对已经注册的用户,获得用户信息。" << std::endl; + for(auto it = users.begin(); it!= users.end();++it){ + tpool.create( + [it]->std::string { + ///这里lambda表达式有返回值 则一定要有return 否则会导致后面的打印出现错误 + /// 即使不打印也会报错 134 (interrupted by signal 6:SIGABRT) + return do_queryuser(it->first);//return + } + ); + std::this_thread::sleep_for(std::chrono::seconds(1));//设置每次登录间隔1s + } + ///通过sleep的方式来等待future就绪(进程执行结束)并不是很安全 + std::cout<< "等待10s-->子线程完成:打印用户信息" << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(10));//等待A中的future就绪 + for(auto it = A.begin(); it != A.end(); ++it){ + //迭代A 并打印用户信息 + /// 134 (interrupted by signal 6:SIGABRT) + std::cout << it->get() << std::endl;//每个future对象只能调用一次get + } + return 0; } +#endif +#endif + +int test1(){//test1:在主线程中 注册 登录 + auto now = std::chrono::steady_clock::now(); // 当前时间 + auto duration = now.time_since_epoch(); + auto seconds = std::chrono::duration_cast(duration); + int N = 2;//注册N个用户 + std::string ret; + for(int i =0;istd::string { + std::cout << do_register(test::username[rand() % 4], test::password[rand() % 4], test::school[rand() % 4], test::phone[rand() % 4]); -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::string { + std::cout << do_login(test::username[rand() % 4], test::password[rand() % 4]); }); - tpool.create([&] { - std::cout << do_queryuser(test::username[rand() % 4]) << std::endl; + tpool.create([&]->std::string { + std::cout << do_queryuser(test::username[rand() % 4]); }); } // 作业要求4:等待 tpool 中所有线程都结束后再退出 return 0; -} +#endif + +#ifndef __for_test__ + for (int i = 0; i < 261114; i++) {//261114 + tpool.create([&]()->void{ + std::cout << do_register(test::username[rand() % 4], test::password[rand() % 4], test::school[rand() % 4], test::phone[rand() % 4]); + + }); + tpool.create([&]()->void { + std::cout << do_login(test::username[rand() % 4], test::password[rand() % 4]); + }); + tpool.create([&]()->void { + std::cout << do_queryuser(test::username[rand() % 4]); + }); + } + + // 作业要求4:等待 tpool 中所有线程都结束后再退出 + return 0; +#endif + +} \ No newline at end of file