Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

完成了hw05 #46

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.associations": {
"map": "cpp"
}
}
28 changes: 28 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -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"
}
233 changes: 205 additions & 28 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,35 @@
#include <string>
#include <thread>
#include <map>
#include <mutex>
#include <vector>
#include <future>

#define __Change__ //用于标记 时间标签的使用方式,定义这个宏定义则使用std::chrono,否则使用 time
//#define __for_test__ //用于标记 测试函数,定义这个宏定义 则使用有返回值的std::async, 否则没有返回值

struct User {
std::string password;
std::string school;
std::string phone;
};
};//用户信息

std::map<std::string, User> users;//<用户名,用户信息>

#ifdef __Change__
std::map<std::string, std::chrono::seconds> has_login;//<用户名,登录时刻>
#endif

std::map<std::string, User> users;
#ifndef __Change__
std::map<std::string, long> 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 "注册成功";
Expand All @@ -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<std::chrono::seconds>(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<std::future<std::string>> A;//用于保存将子线程的返回对象future
#endif

struct ThreadPool {
#ifdef __for_test__
///用于test2 test1
void create(std::function<std::string()> 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<void()> 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<std::string>中
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<std::string>就绪
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<std::string>就绪
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<std::string>就绪
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<std::chrono::seconds>(duration);
int N = 2;//注册N个用户
std::string ret;
for(int i =0;i<N;i++){
ret = do_register(test::username[i],test::password[i],test::school[i],test::phone[i]);//用户注册
std::cout << "User:" << test::username[i] << "; " << ret << std::endl;
}
int M = 3;//登录M个用户
for (int i=0;i<M;i++){
ret = do_login(test::username[i],test::password[i]);
std::cout << "User:" << test::username[i] << "; " << ret << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(5));
for (int i=0;i<M-1;i++){
ret = do_login(test::username[i],test::password[i]);
std::cout << "User:" << test::username[i] << "; " << ret << std::endl;
}

return 0;
}


int main() {//test0
#ifdef __for_test__
///由于每一个线程返回的future都会保存到A中,导致 Resource temporarily unavailable
/// 奇怪的是 这里lambda表达式设定来返回值 但是我没有return 却没有报错
for (int i = 0; i < 261114; i++) {
tpool.create([&]->std::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

}