问题描述
使用VC2010或以上版本编写一个多线程注册验证程序,要求:
- 通过对话框输入若干人的学号和姓名,并存入列表中作为注册记录。
- 用户输入一个学号,程序能通过多线程的方式与注册记录比对来验证其是否已注册,并弹出提示框。
解决方案
以下程序基于VS2019设计,VS2010可能无法运行。
首先新建一个MFC应用
应用程序类型选择基于对话框,点击完成
在资源视图打开以下界面,开始制作GUI界面
从工具箱中添加控件,本项目主要用到三个控件,按钮Button、可编辑文本框Edit Control、静态文本框Static Text
制作好的GUI如下(界面有点简陋,求轻喷):
完成GUI制作后,我们就可以往StudengsManageSystemDlg.cpp中添加代码了。根据题目的要求,我们需要保存学生的学号和姓名,因此我们创建一个包含学号、姓名以及一个构造函数的学生类,为了方便之后的查询对比,将学号用long long型数据保存。
// 创建一个学生类
class Student
{
public:
long long SID;
CString Name;
Student(long long sid, CString name)
{
SID = sid;
Name = name;
}
};
接下来我们需要一个列表来保存每个学生类的实例
// 新建一个学生列表
vector<Student> stulist;
然后在GUI设计界面双击保存
按钮,跳转到这个保存
按钮的回调函数
void CStudentsManageSystemDlg::OnBnClickedButton1()
{
CString sid;
CString name;
// 将文本框1的内容输出到sid
GetDlgItem(IDC_EDIT3)->GetWindowText(sid);
// 将文本框2的内容输出到name
GetDlgItem(IDC_EDIT4)->GetWindowText(name);
// 判断待保存的学号和姓名中是否有空值
if (name == "" || sid == "")
{
CString str_prompt = CString("提示框");
CString str = CString("学号/姓名不能为空!");
MessageBox(str, str_prompt, MB_OK);
return;
}
// 学号必须为数字,如果存在非数字则返回,并弹出提示框
for (int i = 0; i < sid.GetLength(); i++)
{
if (sid[i] < '0' || sid[i] > '9')
{
CString str_prompt = CString("提示框");
CString str = CString("请输入正确的学号!");
MessageBox(str, str_prompt, MB_OK);
return;
}
}
// 将上述内容存到学生列表中
stulist.push_back(Student(_ttoll(sid), name));
}
由于题目要求使用多线程的方式来验证是否注册,所以需要编写一个查询函数search_task(long long sid)
,它的形参是待查询的学号。
void search_task(long long sid)
{
if (stulist.size() == 0)
{
CString str_prompt = CString("提示框");
CString str = CString("学生列表为空!");
MessageBox(NULL, str, str_prompt, MB_OK);
return;
}
for (int i = 0; i < stulist.size(); i++)
{
if (stulist[i].SID == sid)
{
CString str_prompt = CString("提示框");
MessageBox(NULL, CString("姓名为:") + stulist[i].Name, str_prompt, MB_OK);
break;
}
else
{
if (i == stulist.size() - 1)
{
CString str_prompt = CString("提示框");
CString str = CString("未注册!");
MessageBox(NULL, str, str_prompt, MB_OK);
}
}
}
}
最后向查询
按钮中添加回调函数
void CStudentsManageSystemDlg::OnBnClickedButton2()
{
CString sid;
GetDlgItem(IDC_EDIT5)->GetWindowText(sid);
// 待查询的学号不能为空
if (sid == "")
{
CString str_prompt = CString("提示框");
CString str = CString("查询学号不能为空!");
MessageBox(str, str_prompt, MB_OK);
return;
}
for (int i = 0; i < sid.GetLength(); i++)
{
if (sid[i] < '0' || sid[i] > '9')
{
CString str_prompt = CString("提示框");
CString str = CString("请输入正确的学号!");
MessageBox(str, str_prompt, MB_OK);
return;
}
}
long long SID = _ttoll(sid);
// 开启查询线程
thread t(search_task, SID);
// 必须将线程join或者detach,子线程结束后主进程才可以退出
t.detach();
}
运行程序
完成上述操作后,就可以测试程序了。
- 保存
2017000000001 王小明
2017000000002 王大明
,并查询2017000000001
以及2017000000003
,得到以下结果。
- 保存
2017xxxxxxxx1
,弹出提示框,结果正确。
结论
测试程序时,可能没有体现出多线程的作用,因为输入的样本数较少,执行查询任务时也就一瞬间的事。但是样本数量比较大时,查询任务将会耗费比较多的时间,如果将查询任务放在回调函数中执行,将会导致在查询过程中,系统无法响应,表现为系统卡住。
当然当样本数较大时,还可能发生前一次查询还没结束,另一次查询就发起了的情况,这时候两次查询都需要用到学生列表,所以
由于时间限制,并没有将学生列表中的数据保存到一个本地文件中,所以本程序中所有输入的数据都保存在一个动态列表中,当程序关闭时,这些数据将会丢失。
完整项目在这里(其实按照上述步骤操作应该能得到一个差不多的程序):