文章目录
- 临界区
- MFC 临界区
- 全部代码
- 事件内核对象
- 信号量内核对象
- 互斥量
- MFC 中设置只能有一个窗口
- MFC线程通信
临界区
火车票买票问题
#include<stdio.h>
#include <Windows.h>
/*
临界区(关键段)
*/
CRITICAL_SECTION g_cs;
int g_count = 500;//票数
DWORD WINAPI ThreadProc1(LPVOID lpParam)
{
while (g_count > 0)
{
//进入临界区,对资源进行枷锁,同时只能有一个线程访问
EnterCriticalSection(&g_cs);
printf("窗口1:卖出一张票,还剩:%d张票\n", g_count);
g_count--;
//离开临界区
LeaveCriticalSection(&g_cs);
//在临界区尽量不要有Sleep
}
return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
while (g_count > 0)
{
//进入临界区,对资源进行枷锁,同时只能有一个线程访问
EnterCriticalSection(&g_cs);
printf("窗口2:卖出一张票,还剩:%d张票\n", g_count);
g_count--;
//离开临界区
LeaveCriticalSection(&g_cs);
}
return 0;
}
int main()
{
//初始化临界区
InitializeCriticalSection(&g_cs);
//创建线程
CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
while (1)
{
}
return 0;
}
MFC 临界区
创建线程
void CCriticalSectionMFCDlg::OnBnClickedButton1()
{
//第一个是线程函数的指针
//第二个是传递给这个函数的参数
//后面几个都是默认参数,可以省略
AfxBeginThread(ThreadProc1, this);
AfxBeginThread(ThreadProc2, this);
}
临界区关键段
CCriticalSection g_cs;//关键段
线程处理函数
//线程1
UINT ThreadProc1(LPVOID pParam)
{
CCriticalSectionMFCDlg* pDlg = (CCriticalSectionMFCDlg*)pParam;
while (1)
{
g_cs.Lock();
int num1 = rand() % 100;
int num2 = rand() % 100;
g_count++;
//绘制到界面
TCHAR str[100];
wsprintf(str, L"线程1:第%d题:%d+%d=%d", g_count, num1, num2, num1 + num2);
CDC* pDC = pDlg->GetDC();//标识CWnd客户端区域的设备上下文
pDC->TextOut(10, g_count * 20, str);
pDlg->ReleaseDC(pDC);
g_cs.Unlock();
}
return 0;
}
//线程2
UINT ThreadProc2(LPVOID pParam)
{
CCriticalSectionMFCDlg* pDlg = (CCriticalSectionMFCDlg*)pParam;
while (1)
{
g_cs.Lock();
srand((UINT)time(NULL));
int num1 = rand() % 100;
int num2 = rand() % 100;
g_count++;
//绘制到界面
TCHAR str[100];
wsprintf(str, L"线程2:第%d题:%d+%d=%d", g_count, num1, num2, num1 + num2);
CDC* pDC = pDlg->GetDC();//标识CWnd客户端区域的设备上下文
pDC->TextOut(10, g_count * 20, str);
pDlg->ReleaseDC(pDC);
g_cs.Unlock();
}
return 0;
}
全部代码
// CriticalSectionMFCDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "CriticalSectionMFC.h"
#include "CriticalSectionMFCDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CCriticalSectionMFCDlg 对话框
CCriticalSection g_cs;//关键段
int g_count = 0;//题目个数
//线程1
UINT ThreadProc1(LPVOID pParam)
{
CCriticalSectionMFCDlg* pDlg = (CCriticalSectionMFCDlg*)pParam;
while (1)
{
g_cs.Lock();
int num1 = rand() % 100;
int num2 = rand() % 100;
g_count++;
//绘制到界面
TCHAR str[100];
wsprintf(str, L"线程1:第%d题:%d+%d=%d", g_count, num1, num2, num1 + num2);
CDC* pDC = pDlg->GetDC();//标识CWnd客户端区域的设备上下文
pDC->TextOut(10, g_count * 20, str);
pDlg->ReleaseDC(pDC);
g_cs.Unlock();
}
return 0;
}
//线程2
UINT ThreadProc2(LPVOID pParam)
{
CCriticalSectionMFCDlg* pDlg = (CCriticalSectionMFCDlg*)pParam;
while (1)
{
g_cs.Lock();
srand((UINT)time(NULL));
int num1 = rand() % 100;
int num2 = rand() % 100;
g_count++;
//绘制到界面
TCHAR str[100];
wsprintf(str, L"线程2:第%d题:%d+%d=%d", g_count, num1, num2, num1 + num2);
CDC* pDC = pDlg->GetDC();//标识CWnd客户端区域的设备上下文
pDC->TextOut(10, g_count * 20, str);
pDlg->ReleaseDC(pDC);
g_cs.Unlock();
}
return 0;
}
CCriticalSectionMFCDlg::CCriticalSectionMFCDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_CRITICALSECTIONMFC_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CCriticalSectionMFCDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CCriticalSectionMFCDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CCriticalSectionMFCDlg::OnBnClickedButton1)
END_MESSAGE_MAP()
// CCriticalSectionMFCDlg 消息处理程序
BOOL CCriticalSectionMFCDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
srand((UINT)time(NULL));
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CCriticalSectionMFCDlg::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 CCriticalSectionMFCDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CCriticalSectionMFCDlg::OnBnClickedButton1()
{
//第一个是线程函数的指针
//第二个是传递给这个函数的参数
//后面几个都是默认参数,可以省略
AfxBeginThread(ThreadProc1, this);
AfxBeginThread(ThreadProc2, this);
}
事件内核对象
#include<stdio.h>
#include <Windows.h>
/*
事件对象
*/
int g_count = 500;//票数
HANDLE hEvent=NULL;
DWORD WINAPI ThreadProc1(LPVOID lpParam)
{
while (g_count > 0)
{
//一但有信号就立刻马上返回,并且返回WAIT_OBJECT_0 WaitForSingleObject(窗口句柄,等待时间间隔)
//等待超时返回WAIT_TIMEOUT
//失败返回WAIT_FAILED
if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, INFINITE))
{
printf("窗口1:卖出一张票,还剩:%d张票\n", g_count);
g_count--;
//处理完再次设置有信号状态
SetEvent(hEvent);
}
}
return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
while (g_count > 0)
{
if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, INFINITE))
{
printf("窗口2:卖出一张票,还剩:%d张票\n", g_count);
g_count--;
//处理完再次设置有信号状态
SetEvent(hEvent);
}
}
return 0;
}
int main()
{
//创建一个事件对象
/*
第一个参数:安全属性
第二个参数:重置 自动重置无信号状态FALSE,手动重置无信号状态TRUE
第三个参数:有无信号 TRUE 有信号,FALSE无信号
第五个参数:事件对象的名字
*/
hEvent=CreateEvent(NULL,FALSE, FALSE,NULL);
//设置有信号的
SetEvent(hEvent);
//创建线程
CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
while (1)
{
}
return 0;
}
信号量内核对象
#include<stdio.h>
#include<Windows.h>
/*
信号量
*/
int g_count = 0;
HANDLE g_hSemaphore;
//线程处理函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
while (1)
{
if (WAIT_OBJECT_0 == WaitForSingleObject(g_hSemaphore, INFINITE))
{
g_count++;
printf("线程ID:%d,值:%d\n", GetCurrentThreadId(), g_count);
if (g_count >= 20)
{
break;
}
//增加信号量
//1.信号量句柄
//2.增加信号量个数
//3.是否接受原来的信号量
if (!ReleaseSemaphore(g_hSemaphore, 1, NULL))
{
printf("增加信号量:错误代号:%d", GetLastError());
}
}
}
return 0;
}
int main()
{
//创建信号量
//第一个参数:安全属性
//第二个参数:允许几个信号量初始化
//第三个参数:信号量对象的最大数
//第四个参数:信号量的名字
g_hSemaphore=CreateSemaphore(NULL,1,1,NULL);
if (g_hSemaphore == NULL)
{
printf("创建信号量失败。错误代号:%d\n", GetLastError());
return 0;
}
HANDLE arrhThread[10];
for (int i = 0; i < 10; i++)
{
arrhThread[i]=CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
if (arrhThread[i] == NULL)
{
printf("创建信号量失败。错误代号:%d\n", GetLastError());
return 0;
}
}
//等待所有线程的信号
//1.窗口句柄个数
//2.窗口句柄
//3.等待信号量的个数,True等待所有信号量发送信号,FALSE等待一个信号
//4.等待时间
WaitForMultipleObjects(10, arrhThread, TRUE,INFINITE);
printf("所有线程执行完毕\n");
return 0;
}
互斥量
#include<stdio.h>
#include<Windows.h>
/*
互斥对象
*/
int g_count = 500;
HANDLE g_hMutex;
//线程处理函数
DWORD WINAPI ThreadProc1(LPVOID lpParam)
{
while (1)
{
WaitForSingleObject(g_hMutex, INFINITE);
if (g_count > 0)
{
g_count--;
printf("窗口1还剩:%d\n", g_count);
}
else
break;
//释放互斥量
ReleaseMutex(g_hMutex);
}
return 0;
}
//线程处理函数
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
while (1)
{
WaitForSingleObject(g_hMutex, INFINITE);
if (g_count > 0)
{
g_count--;
printf("窗口2还剩:%d\n", g_count);
}
else
break;
//释放互斥量
ReleaseMutex(g_hMutex);
}
return 0;
}
DWORD WINAPI ThreadProc3(LPVOID lpParam)
{
while (1)
{
WaitForSingleObject(g_hMutex, INFINITE);
if (g_count > 0)
{
g_count--;
printf("窗口3还剩:%d\n", g_count);
}
else
break;
//释放互斥量
ReleaseMutex(g_hMutex);
}
return 0;
}
int main()
{
//创建互斥内核对象
//1.安全属性:NULL
//2.信号状态:FALSE 有信号状态
//3.信号名称:NULL表示匿名
g_hMutex=CreateMutex(NULL, FALSE, NULL);
//创建3个线程
CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
CreateThread(NULL, 0, ThreadProc3, NULL, 0, NULL);
while (1);
return 0;
}
MFC 中设置只能有一个窗口
//创建一个互斥对象
//GUID(全局唯一标识符),点击工具创建GUID
HANDLE hMutex=CreateMutex(NULL, TRUE, L"{EBC3EAE2-3107-4F3C-9B8B-3FD4D2023D10}");
if (hMutex)
{
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
AfxMessageBox(L"此程序已经运行了");
return TRUE;
}
}
MFC线程通信
MFC 线程通信