模拟售票大厅实例——多线程时访问共享变量时的安全(CMutex或CCriticalSection的应用)

article/2025/10/29 6:02:23

 

当程序运行时,可以通过多线程来提高程序运行的效率和拥有更好的体验。但多线程(或多进程)同时也带来很多的问题:最严重的莫过于对同一个对象或变量访问时,由于线程运行异步的原因,会造成程序运行出现无法控制的重大错误。对此,MFC有控制线程或进程同步的封装类:如CMutex或CCriticalSection等等。详细用法不说,直接上代码:

源码:https://download.csdn.net/download/weixin_44027440/11428840

效果图:

SaleTickets.h


// SaleTickets.h: PROJECT_NAME 应用程序的主头文件
//#pragma once#ifndef __AFXWIN_H__#error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif#include "resource.h"		// 主符号// CSaleTicketsApp:
// 有关此类的实现,请参阅 SaleTickets.cpp
//class CSaleTicketsApp : public CWinApp
{
public:CSaleTicketsApp();// 重写
public:virtual BOOL InitInstance();// 实现DECLARE_MESSAGE_MAP()
};extern CSaleTicketsApp theApp;

SaleTickets.cpp


// SaleTickets.cpp: 定义应用程序的类行为。
//#include "stdafx.h"
#include "SaleTickets.h"
#include "SaleTicketsDlg.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif// CSaleTicketsAppBEGIN_MESSAGE_MAP(CSaleTicketsApp, CWinApp)ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()// CSaleTicketsApp 构造CSaleTicketsApp::CSaleTicketsApp()
{// TODO: 在此处添加构造代码,// 将所有重要的初始化放置在 InitInstance 中
}// 唯一的 CSaleTicketsApp 对象CSaleTicketsApp theApp;// CSaleTicketsApp 初始化BOOL CSaleTicketsApp::InitInstance()
{CWinApp::InitInstance();// 创建 shell 管理器,以防对话框包含// 任何 shell 树视图控件或 shell 列表视图控件。CShellManager *pShellManager = new CShellManager;// 激活“Windows Native”视觉管理器,以便在 MFC 控件中启用主题CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));// 标准初始化// 如果未使用这些功能并希望减小// 最终可执行文件的大小,则应移除下列// 不需要的特定初始化例程// 更改用于存储设置的注册表项// TODO: 应适当修改该字符串,// 例如修改为公司或组织名SetRegistryKey(_T("应用程序向导生成的本地应用程序"));CSaleTicketsDlg dlg;m_pMainWnd = &dlg;INT_PTR nResponse = dlg.DoModal();if (nResponse == IDOK){// TODO: 在此放置处理何时用//  “确定”来关闭对话框的代码}else if (nResponse == IDCANCEL){// TODO: 在此放置处理何时用//  “取消”来关闭对话框的代码}else if (nResponse == -1){TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");}// 删除上面创建的 shell 管理器。if (pShellManager != nullptr){delete pShellManager;}#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)ControlBarCleanUp();
#endif// 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,//  而不是启动应用程序的消息泵。return FALSE;
}

SaleTicketsDlg.h】 


// SaleTicketsDlg.h: 头文件
//#pragma once// CSaleTicketsDlg 对话框
class CSaleTicketsDlg : public CDialogEx
{
// 构造
public:CSaleTicketsDlg(CWnd* pParent = nullptr);	// 标准构造函数// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_SALETICKETS_DIALOG };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持// 实现
protected:HICON m_hIcon;// 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()public:static UINT SaleAProc(LPVOID pParam);static UINT SaleBProc(LPVOID pParam);static UINT  AutoSaleAProc(LPVOID pParam);static UINT  AutoSaleBProc(LPVOID pParam);afx_msg void OnBnClickedButtonSaleA();afx_msg void OnBnClickedButtonSaleB();afx_msg void OnBnClickedButtonAutosale();CWinThread *m_pSaleAThread;CWinThread *m_pSaleBThread;afx_msg void OnBnClickedButtonReset();
};

SaleTicketsDlg.cpp】 


// SaleTicketsDlg.cpp: 实现文件
//#include "stdafx.h"
#include "SaleTickets.h"
#include "SaleTicketsDlg.h"
#include "afxdialogex.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif//全局变量
int nTickets;
CMutex	 g_mutex(FALSE, _T("Tickets"));
//CCriticalSection g_mutex;// CSaleTicketsDlg 对话框CSaleTicketsDlg::CSaleTicketsDlg(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_SALETICKETS_DIALOG, pParent)
{m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);//fdd addnTickets = TICKETSNUM;}void CSaleTicketsDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CSaleTicketsDlg, CDialogEx)ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON_SALE_A, &CSaleTicketsDlg::OnBnClickedButtonSaleA)ON_BN_CLICKED(IDC_BUTTON_SALE_B, &CSaleTicketsDlg::OnBnClickedButtonSaleB)ON_BN_CLICKED(IDC_BUTTON_AUTOSALE, &CSaleTicketsDlg::OnBnClickedButtonAutosale)ON_BN_CLICKED(IDC_BUTTON_RESET, &CSaleTicketsDlg::OnBnClickedButtonReset)
END_MESSAGE_MAP()// CSaleTicketsDlg 消息处理程序BOOL CSaleTicketsDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动//  执行此操作SetIcon(m_hIcon, TRUE);			// 设置大图标SetIcon(m_hIcon, FALSE);		// 设置小图标// TODO: 在此添加额外的初始化代码//fdd addSetDlgItemInt(IDC_EDIT_TICKETS, nTickets);return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。void CSaleTicketsDlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}
}//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CSaleTicketsDlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(m_hIcon);
}UINT	CSaleTicketsDlg::SaleAProc(LPVOID pParam) {//解读传送的变量CWnd *pDlg = (CWnd *)pParam;//上锁g_mutex.Lock();if (nTickets > 0) {Sleep(1);CString strName;pDlg->GetDlgItemText(IDC_EDIT_NAME_A, strName);//购票人姓名CListBox *lbSaleA = (CListBox *)pDlg->GetDlgItem(IDC_LIST_NAME_A);//售票窗口ACString s;s.Format(_T("%d--->"), TICKETSNUM+1 - nTickets);s += strName;lbSaleA->AddString(s);pDlg->SetDlgItemInt(IDC_EDIT_TICKETS, --nTickets);}else {AfxMessageBox(_T("你来晚了,票已经卖完了!"));}//解锁g_mutex.Unlock();return 0;}
UINT	CSaleTicketsDlg::SaleBProc(LPVOID pParam) {//解读传送的变量CWnd *pDlg = (CWnd *)pParam;//上锁g_mutex.Lock();if (nTickets > 0) {Sleep(1);CString strName;pDlg->GetDlgItemText(IDC_EDIT_NAME_B, strName);//购票人姓名CListBox *lbSaleB = (CListBox *)pDlg->GetDlgItem(IDC_LIST_NAME_B);//售票窗口ACString s;s.Format(_T("%d--->"), TICKETSNUM+1 - nTickets);s += strName;lbSaleB->AddString(s);pDlg->SetDlgItemInt(IDC_EDIT_TICKETS, --nTickets);}else {AfxMessageBox(_T("你来晚了,票已经卖完了!"));}//解锁g_mutex.Unlock();return 0;}void CSaleTicketsDlg::OnBnClickedButtonSaleA()
{// TODO: 在此添加控件通知处理程序代码m_pSaleAThread = AfxBeginThread(SaleAProc,(LPVOID)this);
}void CSaleTicketsDlg::OnBnClickedButtonSaleB()
{// TODO: 在此添加控件通知处理程序代码m_pSaleAThread = AfxBeginThread(SaleBProc, (LPVOID)this);
}void CSaleTicketsDlg::OnBnClickedButtonAutosale()
{// TODO: 在此添加控件通知处理程序代码m_pSaleAThread=AfxBeginThread(AutoSaleAProc, (LPVOID)this);m_pSaleBThread = AfxBeginThread(AutoSaleBProc, (LPVOID)this);}UINT  CSaleTicketsDlg::AutoSaleAProc(LPVOID pParam) {//解读传送的变量CWnd *pDlg = (CWnd *)pParam;while (1) {g_mutex.Lock();if (nTickets > 0) {Sleep(1);CString strName;strName.Format(_T("%d--->姓名:无"), TICKETSNUM+1 - nTickets);CListBox *lbSaleA = (CListBox *)pDlg->GetDlgItem(IDC_LIST_NAME_A);//售票窗口AlbSaleA->AddString(strName);pDlg->SetDlgItemInt(IDC_EDIT_TICKETS, --nTickets);g_mutex.Unlock();}else{AfxMessageBox(_T("窗口A提示您:票已经卖完了!"));g_mutex.Unlock();break;}}return 0;
}
UINT  CSaleTicketsDlg::AutoSaleBProc(LPVOID pParam) {//解读传送的变量CWnd *pDlg = (CWnd *)pParam;while (1) {g_mutex.Lock();if (nTickets > 0) {Sleep(1);CString strName;strName.Format(_T("%d--->姓名:无"), TICKETSNUM+1 - nTickets);CListBox *lbSaleB = (CListBox *)pDlg->GetDlgItem(IDC_LIST_NAME_B);//售票窗口AlbSaleB->AddString(strName);pDlg->SetDlgItemInt(IDC_EDIT_TICKETS, --nTickets);g_mutex.Unlock();}else{AfxMessageBox(_T("窗口B提示您:票已经卖完了!"));g_mutex.Unlock();break;}}return 0;
}void CSaleTicketsDlg::OnBnClickedButtonReset()
{// TODO: 在此添加控件通知处理程序代码nTickets = TICKETSNUM;SetDlgItemInt(IDC_EDIT_TICKETS, nTickets);SetDlgItemText(IDC_EDIT_NAME_A, _T(""));SetDlgItemText(IDC_EDIT_NAME_B, _T(""));((CListBox *)GetDlgItem(IDC_LIST_NAME_A))->ResetContent();((CListBox *)GetDlgItem(IDC_LIST_NAME_B))->ResetContent();}

 

 


http://chatgpt.dhexx.cn/article/Vet7BNCb.shtml

相关文章

在MFC下面实际演示CCriticalSection 的使用

Q&#xff1a;CCriticalSection是什么&#xff1f; A&#xff1a;CCriticalSection是一种线程同步策略 或者说技术 或者方法 总之呢就是这么个意思。。。。 参考资料&#xff1a; http://blog.csdn.net/akof1314/article/details/5773076 http://www.cnblogs.com/hlxs/archi…

Android对话框总结(普通对话框,单选对话框,多选对话框,自定义对话框)

个人推荐: &#x1f4e2;&#x1f4e2;&#x1f4e2; 前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下 "通俗易懂&#xff0c;风趣幽默"&#xff0c;感觉非常有意思,忍不住分享一下给大家。点击跳转到教程。 一:AlterDialog对话框 二:普通对话框 运行效果…

Android对话框显示输入框

在弹出的对话框显示输入框有两种方法&#xff1a; 法一&#xff1a;新建一个布局&#xff0c;并在对话框中引用它。 法二&#xff1a;直接在Activity中定义Edit并在对话框中用getText方法得到输入信息。

Android对话框的使用

Android对话框的使用 对话框&#xff08;Dialog&#xff09;是Android系统在Activity或者其他组件运行过程中提供的一种提示机制。它可以帮助应用完成一些必要的提示功能&#xff0c;同时提供一些与用户交互的功能。 对话框分为很多种&#xff0c;下面将一一介绍…

android 自定义对话框

// 基础库 implementation com.github.goweii.AnyLayer:anylayer:2.5.0 // 通用弹窗&#xff08;依赖基础库&#xff09; implementation com.github.goweii.AnyLayer:anylayer-common:2.5.0 编写dialog_layout 布局 <?xml version"1.0" encoding"utf-8&qu…

Android对话框的使用总结

一&#xff0e;相关概念 一个对话框一般是一个出现在当前Activity之上的一个小窗口. 处于下面的Activity失去焦点, 对话框接受所有的用户交互. 对话框一般用于提示信息和与当前应用程序直接相关的小功能. Android API 支持下列类型的对话框对象: &#xff08;一&#x…

Android对话框控件读写,Android 对话框控件

对话框控件 一、概述 对话框是 UI 设计中常用的控件&#xff0c;在windows操作系统中&#xff0c;对话框可分为模式对话框和非模式对话框。 模式对话框在使用时&#xff0c;项目中其它UI是不允许操作的&#xff0c;如保存对文件话框 非模式对话框允许操作其它的 UI Android 的对…

Android对话框总结

一、什么是对话框&#xff1f; 一种次要窗口&#xff0c;包含按钮和各种选项&#xff0c;通过它们可以完成特定命令或任务。 查找和替换对话框 对话框与窗口有区别&#xff0c;它没有最大化按钮、没有最小化按钮、大都不能改变形状大小。&#xff08;“打开文件”对话框是可以改…

Android常用对话框

学习目标&#xff1a; 两周入门Android 学习内容&#xff1a; 常见对话框: 对话框是程序与用户交互的一种方式&#xff0c;通常用于显示当前程序提示信息以及相关说明,以小窗口形式展现 普通对话框&#xff1a; 通过AlertDialog.Builder(this).create来创建对话框最后通过…

了解Android布局,了解Android对话框布局

我正在为我的android应用程序做一个简单的自定义对话框&#xff0c;只显示一个搜索栏。然而&#xff0c;这个简单任务的复杂性让我很烦。了解Android对话框布局 我的对话框布局如下&#xff1a;在代码中创建 android:orientation"vertical" android:layout_width&quo…

Android对话框(普通对话框、单选对话框、多选对话框、进度条对话框)

一、普通对话框 // 通过builder 构建器来构造AlertDialog.Builder builder = new Builder(this);builder.setTitle("警告");builder.setMessage("你好么 ");builder.setPositiveButton("好", new OnClickListener() {@Overridepublic void onCl…

android 对话框窗口,Android 对话框详解(一)

对话框是程序运行中的弹出窗口。例如&#xff0c;当用户要删除一个联系方式时&#xff0c;会弹出一个 对话框&#xff0c;让用户确认是否真的要删除。 Android系统提供了四种对话框:警告对话框 (AlertDialog)、进度对话框(ProgressDialog)、日期选择对话框(DatePickerDialog)和…

Android对话框

(不足之处,多多担待) 一: 对话框的种类 1:提示对话框 2:自定义对话框 3:弹出对话框 二:设置对话框的详细步骤 1:提示对话框 在activity中设置代码实现功能 , 第一步实例化对话框 第二步是设置对话框的提示内容 ,有4个主要方法 (窗贴提示内容:setTitle() / setMessage()…

Android常用对话框大全——Dialog

唉&#xff01;最近一直忙碌着写项目以至于都没有空出点时间来总结近期的学习&#xff0c; 记录学习到的东西…现在正好有时间了就该好好记录一下学习的过程了。 今天就来谈谈开发中经常用的到的一个控件——Dialog&#xff0c;对话框一般我们就用来提示一些信息给用户&#…

Android 对话框(Dialog)

对话框是提示用户做出决定或输入额外事件的小窗口。对话框不会填充屏幕&#xff0c;通常用于需要用户采取行动才能继续执行的模式事件。 Dialog类是对话框的基类&#xff0c;我们可以使用Dialog来构建一个对话框。但Android建议避免直接使用Dialog&#xff0c;而应该使用其子类…

android十大常用对话框

Android十大常用对话框 一、对话框效果二、代码 最近老师叫我们整理android常用的对话框&#xff0c;我整理了十种对话框&#xff0c;用于分享交流&#xff0c;希望指正&#xff01; 一、对话框效果 主界面 1.普通对话框 2.单选对话框 3.多选对话框 4.列表对话框 5.不带进…

Android常用的几种对话框

1文本提示对话框 AlertDialog.Builder b new AlertDialog.Builder(this);//this为上下文&#xff0c;如果在本类里显示&#xff0c;通常使用this b.setTitle("标题");/对话框标题 b.setMessage("可能会删除某个文件");//提示文本 …

Android对话框的详细介绍(提示对话框,自定义对话框)

简介&#xff1a; 我们都知道在Android开发中&#xff0c;当我们的程序在与用户交互时&#xff0c;用户会得到一定的反馈&#xff0c;其中以对话框的形式的反馈还是比较常见的&#xff0c;接下来我们来介绍几种常见的对话框的基本使用。 前置准备&#xff1a;&#xff08;文章…

WinInet 和 WinHttp 有何区别?

背景 WinInet和WinHttp是windows平台下提供了两套独立的网络库&#xff0c;按照微软官方的说法&#xff0c; WinInet的优势在于client-端的应用&#xff0c;而WinHttp更适用于server-端编程。从名称上我们可以看出WinHttp在Http协议应用方面要比WinInet更加专业&#xff0c;Win…

使用WinHTTP与服务器通讯

WinHTTP 的工作流程如下 一.初始化WinHTTP 在与服务器交互之前, 必须用调用WinHttpOpen进行初始化,WinHttpOpen创建一个会话,并返回该会话的句柄,接着有了这个句柄, WinHttpConnect就能指定一个目标服务器 注意:调用了WinHttpConnect并不意味着和服务器建立了真正的连接 二.打…