当程序运行时,可以通过多线程来提高程序运行的效率和拥有更好的体验。但多线程(或多进程)同时也带来很多的问题:最严重的莫过于对同一个对象或变量访问时,由于线程运行异步的原因,会造成程序运行出现无法控制的重大错误。对此,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();}

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

  1. java多线程同步 多窗口卖票实例_java多线程之火车售票系统模拟实例

    1.前言 为了学习多线程共享与通信,我们模拟一个火车售票系统,假设有10张火车票,三个窗口(也就是三个线程)同时进行售票. 2.非同步代码 package com.tl.skyLine.thread; ...

  2. 利用JAVA多线程模拟售票系统,对统一资源进行处理

    首先多线程处理统一资源的方式有两种 分别介绍一下两者的区别 synchronized与Lock的区别 1.Lock不是Java语言内置的,synchronized是Java语言的关键字 2.synch ...

  3. Java模拟售票窗口代码_java多线程模拟售票,多个窗口售票

    package com.ma.thread001; /** * 多线程模拟售票,多个窗口售票 * @author ma * */ public class SellTicktDemo implemen ...

  4. servlet单实例多线程 ---线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。(所有建议不要在servlet中定义成员变

    Servlet 单例多线程 Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servl ...

  5. servlet单实例多线程模式

    Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...

  6. java 模拟火车站售票系统_模拟售票系统java编程

    模拟售票系统java编程 /* 项目:用多线程设计一个模拟火车站售票大厅的工作情形. 问题描述:火车站有许多售票窗口,有些开放,有些不开放.顾客进入火车站售票厅后,到某个售票窗口排队等候,排到了就办理 ...

  7. 操作系统:模拟售票功能

    以下程序是模拟售票功能,使用临界区对象,其中SellPro_1,SellPro_2两个函数分别对应两个售票进程,一次售出一张票. //模拟售票程序 #include <windows.h> ...

  8. JSP —— Servlet 单实例多线程模式

    转载自:http://kakajw.iteye.com/blog/920839 前言:Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.由于Servlet/JSP ...

  9. java 学习~多线程通信 使用共享变量 例子和解释

    多线程互相通信一般使用共享变量.. 完整验证代码: main 方法 public class Test5 {public static void main(String[] args) {Datax ...

最新文章

  1. 堡垒机jumpserver集群部署
  2. oracle celient 作用,WebLogic Server 10.3 SSL配置及SSL协议传输的WebSevice调用.doc
  3. java实现 k nn算法_数据挖掘(二)——Knn算法的java实现
  4. Centos 6.0/ Nginx 安装与配置
  5. 02.生成、打包、部署和管理应用程序及类型
  6. [转]用C#编写ActiveX控件(一)
  7. C++/C语言实现HTTP的GET和POST请求
  8. go语言 panic
  9. iOS开发中常用的宏
  10. 如何使用SVG生成超酷的页面预加载素描动画效果
  11. 代码雨代码源复制_黑色帝国中代码雨如何实现?用python就可以了
  12. 安装ie9提示未能完成安装_升级Internet Explorer未能完成安装四种解决措施
  13. 基于3D人像复原技术的试衣平台
  14. Python自动采集微信联系人
  15. 2021-06-22 加水印后原本EXCEL内容被覆盖
  16. 电脑C盘怎么清理到最干净
  17. ping命令TTL的意思
  18. 互斥 互斥的解决方案
  19. 专访Alasend万能登陆器创作团队
  20. ETL工具之Informatica

热门文章

  1. 大学“电路分析基础”试题合集第七章
  2. CALLBACK 函数
  3. 【博弈论】威佐夫博弈
  4. java byte数组操作_Java byte数组操纵方式代码实例解析
  5. 高校实验室安全VR教育培训系统
  6. 经典游戏回顾之现代战争
  7. Android音频子系统(五)------AudioFlinger处理流程
  8. hal库模拟量_无ADC采集模块的单片机对模拟信号的处理
  9. Yield Guild Games 收购 Genesis NFT Eggs 并登陆农场模拟游戏 Crypto Unicorns
  10. Redis set值时过期时间重置问题