抢红包练习

第一步:在第一个文本框中输入一个值,比如1000;
第二步:点击抢红包,同时创建3个线程,每个线程循环进行抢红包的操作,每次抢50;
第三步:使用Mutex进行线程控制,当第一个文本框中的值<50时,强红包线程结束.
特别说明:
1、四个文本框中的值总和应该为1000
2、强红包线程每次延时50毫秒.
3、使用WaitForMultipleObjects监听所有线程,当线程全部结束后,调用CloseHandle关闭句柄.

下面是代码实现,我是用MFC实现的。

// MutexExDlg.h : 头文件
// #pragma once // CMutexExDlg 对话框
class CMutexExDlg : public CDialogEx
{
// 构造
public:
CMutexExDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据
enum { IDD = IDD_MUTEXEX_DIALOG }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
static HANDLE hThread[];
static HANDLE m_Mutex;
static DWORD WINAPI ThreadProc0(LPVOID lpParameter);
static DWORD WINAPI ThreadProc1(LPVOID lpParameter);
static DWORD WINAPI ThreadProc2(LPVOID lpParameter);
static DWORD WINAPI ThreadProc3(LPVOID lpParameter); // 实现
protected:
HICON m_hIcon; // 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
virtual BOOL PreTranslateMessage(MSG* pMsg);
afx_msg void OnBnClickedButton1();
static int m_Edit0;
static int m_Edit1;
static int m_Edit2;
static int m_Edit3;
};
// MutexExDlg.cpp : 实现文件
// #include "stdafx.h"
#include "MutexEx.h"
#include "MutexExDlg.h"
#include "afxdialogex.h" #ifdef _DEBUG
#define new DEBUG_NEW
#endif // CMutexExDlg 对话框 CMutexExDlg::CMutexExDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CMutexExDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
} void CMutexExDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_Edit0);
DDV_MinMaxInt(pDX, m_Edit0, , );
DDX_Text(pDX, IDC_EDIT2, m_Edit1);
DDV_MinMaxInt(pDX, m_Edit1, , );
DDX_Text(pDX, IDC_EDIT3, m_Edit2);
DDV_MinMaxInt(pDX, m_Edit2, , );
DDX_Text(pDX, IDC_EDIT4, m_Edit3);
DDV_MinMaxInt(pDX, m_Edit3, , );
} BEGIN_MESSAGE_MAP(CMutexExDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CMutexExDlg::OnBnClickedButton1)
END_MESSAGE_MAP() // CMutexExDlg 消息处理程序 BOOL CMutexExDlg::OnInitDialog()
{
CDialogEx::OnInitDialog(); // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
} // 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。 void CMutexExDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), ); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + ) / ;
int y = (rect.Height() - cyIcon + ) / ; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
} //当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMutexExDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
} // 重写虚函数 PreTranslateMessage 屏蔽掉Esc键和Enter键
BOOL CMutexExDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
int keyCode = (int)pMsg->wParam;
if (keyCode == VK_ESCAPE || keyCode == VK_RETURN)
{
return TRUE;
}
}
return CDialogEx::PreTranslateMessage(pMsg);
} HANDLE CMutexExDlg::m_Mutex = NULL;
int CMutexExDlg::m_Edit0 = ;
int CMutexExDlg::m_Edit1 = ;
int CMutexExDlg::m_Edit2 = ;
int CMutexExDlg::m_Edit3 = ;
HANDLE CMutexExDlg::hThread[] = { NULL }; // 抢红包按钮点击事件处理函数
void CMutexExDlg::OnBnClickedButton1()
{
// 获取编辑框内容到str变量
CString str;
GetDlgItem(IDC_EDIT1)->GetWindowText(str);
// CString 转 int
m_Edit0 = _ttoi(str);
m_Edit1 = ;
m_Edit2 = ;
m_Edit3 = ;
// 这里需要创建一个线程 因为 WaitForMultipleObjects 会阻塞住 另外把this指针作为参数传递给线程,用于子线程更新编辑框内容
HANDLE hThread0 = ::CreateThread(NULL, NULL, ThreadProc0, this, NULL, NULL);
CloseHandle(hThread0);
} DWORD WINAPI CMutexExDlg::ThreadProc0(LPVOID lpParameter)
{
// bInitialOwner BOOL,如创建进程希望立即拥有互斥体,则设为TRUE。一个互斥体同时只能由一个线程拥有
// 创建一个互斥体
m_Mutex = ::CreateMutex(NULL, FALSE, L"test");
// 创建三个线程抢红包
hThread[] = ::CreateThread(NULL, NULL, ThreadProc1, lpParameter, NULL, NULL);
hThread[] = ::CreateThread(NULL, NULL, ThreadProc2, lpParameter, NULL, NULL);
hThread[] = ::CreateThread(NULL, NULL, ThreadProc3, lpParameter, NULL, NULL);
// 使用WaitForMultipleObjects监听所有线程,当线程全部结束后,调用CloseHandle关闭句柄.
WaitForMultipleObjects(, hThread, TRUE, -);
::CloseHandle(hThread[]);
::CloseHandle(hThread[]);
::CloseHandle(hThread[]);
::CloseHandle(m_Mutex);
return ;
} // 线程回调函数1
DWORD WINAPI CMutexExDlg::ThreadProc1(LPVOID lpParameter)
{
CMutexExDlg* pDlg = (CMutexExDlg*)lpParameter;
while (true)
{
WaitForSingleObject(m_Mutex, -);
if (m_Edit0 < )
{
break;
}
m_Edit0 = m_Edit0 - ;
m_Edit1 = m_Edit1 + ;
// int 转 CString
CString str0;
str0.Format(_T("%d"), m_Edit0);
// 设置编辑框内容
::SetWindowText(::GetDlgItem(pDlg->m_hWnd, IDC_EDIT1), str0);
CString str1;
str1.Format(_T("%d"), m_Edit1);
::SetWindowText(::GetDlgItem(pDlg->m_hWnd, IDC_EDIT2), str1);
Sleep();
// 释放线程拥有的互斥体的控制权
ReleaseMutex(m_Mutex);
}
return ;
} // 线程回调函数2
DWORD WINAPI CMutexExDlg::ThreadProc2(LPVOID lpParameter)
{
CMutexExDlg* pDlg = (CMutexExDlg*)lpParameter;
while (true)
{
WaitForSingleObject(m_Mutex, -);
if (m_Edit0 < )
{
break;
}
m_Edit0 = m_Edit0 - ;
m_Edit2 = m_Edit2 + ;
CString str0;
str0.Format(_T("%d"), m_Edit0);
::SetWindowText(::GetDlgItem(pDlg->m_hWnd, IDC_EDIT1), str0);
CString str1;
str1.Format(_T("%d"), m_Edit2);
::SetWindowText(::GetDlgItem(pDlg->m_hWnd, IDC_EDIT3), str1);
Sleep();
// 释放线程拥有的互斥体的控制权
ReleaseMutex(m_Mutex);
}
return ;
} // 线程回调函数3
DWORD WINAPI CMutexExDlg::ThreadProc3(LPVOID lpParameter)
{
CMutexExDlg* pDlg = (CMutexExDlg*)lpParameter;
while (true)
{
WaitForSingleObject(m_Mutex, -);
if (m_Edit0 < )
{
break;
}
m_Edit0 = m_Edit0 - ;
m_Edit3 = m_Edit3 + ;
CString str0;
str0.Format(_T("%d"), m_Edit0);
::SetWindowText(::GetDlgItem(pDlg->m_hWnd, IDC_EDIT1), str0);
CString str1;
str1.Format(_T("%d"), m_Edit3);
::SetWindowText(::GetDlgItem(pDlg->m_hWnd, IDC_EDIT4), str1);
Sleep();
// 释放线程拥有的互斥体的控制权
ReleaseMutex(m_Mutex);
}
return ;
}

C++线程同步与互斥之互斥体的更多相关文章

  1. Delphi线程同步(临界区、互斥、信号量)

    当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源. 例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件的字符数.当然,在整个文件调入内存之前,统计它的计数是 ...

  2. Delphi线程同步(临界区、互斥、信号量,包括详细代码)

    当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源. 例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件的字符数.当然,在整个文件调入内存之前,统计它的计数是 ...

  3. C#线程同步(3)- 互斥量 Mutex

    文章原始出处 http://xxinside.blogbus.com/logs/47162540.html 预备知识:C#线程同步(1)- 临界区&Lock,C#线程同步(2)- 临界区&am ...

  4. MFC线程(三):线程同步事件(event)与互斥(mutex)

    前面讲了临界区可以用来达到线程同步.而事件(event)与互斥(mutex)也同样可以做到. Win32 API中的线程事件 HANDLE hEvent = NULL; void MainTestFu ...

  5. 线程同步(windows平台):互斥对象

    一:介绍 互斥对象是系统内核维护的一种数据结构,保证了对象对单个线程的访问权. 二:函数说明 创建互斥对象:    HANDLE CreateMutex(            LPSECURITY_ ...

  6. 线程同步方式之互斥量Mutex

    互斥量和临界区非常相似,只有拥有了互斥对象的线程才可以访问共享资源,而互斥对象只有一个,因此可以保证同一时刻有且仅有一个线程可以访问共享资源,达到线程同步的目的. 互斥量相对于临界区更为高级,可以对互 ...

  7. 【C#进阶系列】28 基元线程同步构造

    多个线程同时访问共享数据时,线程同步能防止数据损坏.之所以要强调同时,是因为线程同步问题实际上就是计时问题. 不需要线程同步是最理想的情况,因为线程同步一般很繁琐,涉及到线程同步锁的获取和释放,容易遗 ...

  8. Delphi 线程同步技术(转)

    上次跟大家分享了线程的标准代码,其实在线程的使用中最重要的是线程的同步问题,如果你在使用线程后,发现你的界面经常被卡死,或者无法显示出来,显示混乱,你的使用的变量值老是不按预想的变化,结果往往出乎意料 ...

  9. C/C++ 实现多线程与线程同步

    多线程中的线程同步可以使用,CreateThread,CreateMutex 互斥锁实现线程同步,通过临界区实现线程同步,Semaphore 基于信号实现线程同步,CreateEvent 事件对象的同 ...

  10. C++线程同步的四种方式(Windows)

    为什么要进行线程同步? 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作.更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解.正常情况下对这种处理结果的 ...

随机推荐

  1. C#中 ??、 ?、 ?: 、?.、?[ ] 问号

    1. 可空类型修饰符(?) 引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; 是正确的,int i=null; 编译器就会报错.为了使值类型也 ...

  2. pytorch保证每次运行使用的随机数都相同的方法

    其实在代码的开头添加下面几句话即可: # 保证训练时获取的随机数都是一样的 init_seed = torch.manual_seed(init_seed) torch.cuda.manual_see ...

  3. time命令_Linux time命令:测量命令的执行时间或者系统资源的使用情况(转)

    原文地址:http://m.biancheng.net/linux/time.html 这里我们要学习的 time 命令是用来测量 Linux 程序执行时间的命令,而不是用来显示系统时间的命令.不是吧 ...

  4. 【LeetCode算法-27】Remove Element

    LeetCode第27题 Given an array nums and a value val, remove all instances of that value in-place and re ...

  5. Linux中添加新硬盘后对硬盘的分区以及挂载

    转自:https://www.linuxidc.com/Linux/2018-06/152958.htm 我将使用VM来进行模拟 先使用df看下我的电脑硬盘信息: df -h 可以看到只有一个sda1 ...

  6. 扩展Redis的Jedis客户端,哨兵模式读请求走Slave集群

    原 扩展Redis的Jedis客户端,哨兵模式读请求走Slave集群 2018年12月06日 14:26:45 温故而知新666 阅读数 897   版权声明:本文为博主原创文章,遵循CC 4.0 b ...

  7. kexue shangwang

    根据实践,pptp.IPsec甚至OpenVPN等kexue上网法已经无法顺利翻越GFW.通过抓包可知,GFW会将pptp的握手期间的ack包吞掉,导致本地一直无法收到服务器端的响应.而OpenVPN ...

  8. mysql查询之部门工资最高的员工

    最近发现一个网站 力扣 查看 上面有很多算法和数据库的题目,做了一下,发现自己平时都疏忽了,因此边做边记录下来 Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 de ...

  9. RAID磁盘阵列结构

    RAID磁盘阵列结构原理其实很简单,就是每块硬盘不插在主板的硬盘接口上了,而是全插在RAID卡上,然后RAID卡再插到主板上,由RAID卡统一管理硬盘,做各种RAID磁盘策略(RAID0,RAID1, ...

  10. SpringBoot读取properties中的属性值

    1.在application.properties中添加以下内容: learn.blog.name=hello learn.blog.title=千回教育系统 2.新增属性关联的类: package ...