16 线程同步

news2024/11/25 23:47:12

文章目录

  • 临界区
    • 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 线程通信

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/716071.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ day44

1、全局变量&#xff0c;int monster 10000;定义英雄类hero&#xff0c;受保护的属性string name&#xff0c;int hp,int attcKk;公有的无参构造&#xff0c;有参构造&#xff0c;虚成员函数void AtK()[blood-0,}&#xff0c;法师类继承自英雄类&#xff0c;私有属性int ap_at…

networkx

import networkx as nx import matplotlib.pyplot as plt# 创建一个空的无向图 G nx.Graph()# 添加节点 G.add_nodes_from([1, 2, 3, 4, 5])# 指定每个节点的位置 pos {1: (0, 0),2: (1, 1),3: (2, 0),4: (1, -1),5: (-1, -1)}# 添加边 G.add_edges_from([(1, 2), (1, 3), (1…

如何在家居行业运用IPD?

家居行业是我国国民经济重要的民生产业和具有显著国际竞争力的产业。家居家装是指对房屋的整体布局、风格、色彩及空间使用进行重新设定&#xff0c;整体的工程服务包含设计、建筑施工、建材生产、装饰及家具产品制造等&#xff0c;涉及装饰装修行业和制造业。家居家装行业内大…

【Redis三】主从复制、哨兵以及Cluster集群

主从复制、哨兵以及Cluster集群 1.Redis高可用2.Redis主从复制2.1 主从复制的作用2.2 主从复制流程 2.3 搭建Redis主从复制2.3.1 安装部署Redis2.3.2 验证主从复制结果 3.Redis哨兵模式3.1 哨兵模式概述3.2 哨兵模式的作用3.3 故障转移机制3.4 主节点的选举3.5 搭建Redis哨兵模…

布尔运算-基于CGAL的布尔运算

前言&#xff1a;vtk提供的布尔运算接口vtkBooleanOperationFilter或是其他的接口&#xff0c;都存在运行不稳定且速度慢的情况&#xff1b;本博文主要使用CGAL库对布尔运算进行优化&#xff0c;希望给各位小伙伴有所帮助&#xff01; CAGL开源库 介绍 CGAL 是一个软件项目&a…

云原生之深入解析Docker容器的网络及其配置

一、Docker 容器网络 Docker 在安装后自动提供 3 种网络&#xff0c;可以使用 docker network ls 命令查看&#xff1a; [rootlocalhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE cd97bb997b84 bridge …

图像的基础操作

1.获取并修改图像中的像素值 img np.zeros((256, 256, 3), np.uint8) # 创建图像px img[100, 100] # 获取&#xff08;100&#xff0c;100&#xff09;点的像素值 blue img[100, 100, 0] # 仅获取&#xff08;100&#xff0c;100&#xff09;蓝色通道的像素值 …

图像的几何变换

1.图像的缩放 用途&#xff1a;对图像的大小尺寸进行调整&#xff0c;使图像放大或缩小。 代码&#xff1a; import cv2 as cvimg cv.imread(img.jpg)rows, cols img.shape[:2]# 使用绝对坐标 res cv.resize(img, (2 * cols, 2 * rows), interpolationcv.INTER_CUBIC)# 使…

面对“神奇的甲方”:如何应对匪夷所思的需求

在工作中&#xff0c;我们常常会遇到一些“神奇的甲方”&#xff0c;他们总是能给我们带来匪夷所思甚至无厘头的需求。本文将分享作者的经历&#xff0c;并提供一些建议&#xff0c;帮助读者应对这些“无理的需求”。 文章目录 方向一&#xff1a;分享那些你遇到的无理需求方向…

音轨分离 spleeter

https://www.cnblogs.com/ytxwzqin/p/12673661.htmlhttps://www.cnblogs.com/ytxwzqin/p/12673661.html伴奏提取福音&#xff0c;人声分离框架Spleeter1、引言对于制作人、DJ以及任何想分离音频进行单独演奏的人来说&#xff0c;将已经混音后的歌曲拆分为人声和伴奏一直是较为h…

Dirichlet Process 1

如下图的一个简单样本&#xff0c;如果我们不知道图中的样本是出自几个高斯分布&#xff0c;那我们如果求这个图中的样本应该归属于几个高斯分布那&#xff1f;直观看上去&#xff0c;有同学可能说是4个&#xff0c;有同学可能说是2个&#xff0c;然而如果是高维数据那&#xf…

2023年艺术品和古董行业研究报告

第一章 行业概况 艺术品通常指的是创造出来为了表达审美、情感或思想的物品&#xff0c;如绘画、雕塑、照片、装置艺术等。艺术品的价值常常来自于它的创新性、技术精湛以及艺术表达的深度和力度。此外&#xff0c;艺术家的名气和作品的历史背景也会影响其价值。 古董则通常指…

Dev C++ 建立项目 导入代码

首先 建立项目 文件->新建->建项目 会自己添加一个main.cpp 的文件&#xff0c;不需要的话&#xff0c;可以右键移除文件。 往项目里添加文件&#xff1b; 添加后&#xff1a; 编译运行&#xff0c;成功&#xff1b;

【shell】正则表达式:常见通配符、元字符与转义符

文章目录 一. 定义二. 常见通配符1. 匹配一个1.1 " . " 点符号1.2. " ? "符号&#xff1a;代表任意一个1.3. " $ "符号&#xff1a;匹配尾部1.4. " [] "符号1.5. " ^ "符号和" ! "符号 2. 匹配多个2.1. " *…

数据结构-树、二叉树

一、概念 1、树的概念 树是一种非线性的数据结构&#xff0c;它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树&#xff0c;是因为它看起来像是一棵倒挂的树&#xff0c;也就是说它的根在上&#xff0c;而叶子在下。 如果一个数的结点n为0&#xff0c;那么这…

图论算法:DFS求有向图或无向图两点间所有路径及最短路径

1、目的 根据有向图获取指定起终点的所有路径,包括最长和最短路径。 2、示例效果 2.1 原始数据 路线起终点整理如下: // 共计12个顶点,19条边。 (起点,终点,1)最后的1代表起点终点是连通的。 起点,终点,1:2 4 1 起点,终点,1:9 10 1 起点,终点,1:8 11 1 起点…

易基因: RRBS揭示基于DNA甲基化驱动基因的肾透明细胞癌预后模型的鉴定和验证|项目文章

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 肾细胞癌&#xff08;RCC&#xff09;是最常见的肾癌亚型&#xff0c;每年超400万例新发病例&#xff0c;是泌尿系统恶性肿瘤导致的第二大死因。2%-70%的RCC为透明细胞RCC&#xff08;Cl…

node.js使用nodemailer发送阿里云企业邮箱的邮件

百度一搜就能搜到各种博客例子&#xff0c;但是有个问题&#xff1a;有些参数写的不明不白的&#xff0c;我在发送的时候总是报错 后面看到了一篇博客&#xff1a; 基于nodemailer使用阿里云企业邮箱发送邮件&#xff08;526错误的解决&#xff09; 注意几点&#xff1a; …

【现场问题】flink-cdc,sql一直校验不通过,为什么,明明sql没有错误

flink-cdc 问题展示问题解决校验结果 问题展示 这里的flink-cdc的sql对了好几遍&#xff0c;都没问题&#xff0c;包括单个执行create&#xff0c;也是显示校验通过 如图&#xff1a; 但是多个一起就报错了&#xff1a; java.lang.IllegalArgumentException: only single state…

奇点云DataSimba R4.9 LTS发布:稳定性加固,架构升级,142项功能上新

不久前&#xff0c;奇点云的数据云全系产品如期发布新一季商业化版本更新&#xff1a; 数据云平台DataSimba&#xff1a;R4.9 LTS版发布&#xff0c;稳定性全面加固&#xff0c;功能上新&#xff1b;自R4系列起架构升级&#xff0c;封装底层复杂性&#xff0c;支撑上层快速构建…