VC++线程同步(二) Mutex互斥量的例子

同步对象使用实例

Win32窗口的建立:

我们将要学习的使用,分别是:互斥量,临界区,事件,信号量.所以我们需要一个窗口,呈现四种四种同步对象状态.

首先创建一个Win32项目,不要选空项目;

我们需要四个小窗口,先找到注册主窗口的代码。

ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc= WndProc;
wcex.cbClsExtra= 0;
wcex.cbWndExtra= 0;
wcex.hInstance= hInstance;
wcex.hIcon= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT1));
wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName= MAKEINTRESOURCE(IDC_WIN32PROJECT1);
wcex.lpszClassName= szWindowClass;
wcex.hIconSm= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}

不重要的部分(就是Win32窗口流程):先创建的是注册一个主窗口的Windows的类结构,并且赋值给他一个窗口的Proc函数,然后调用InitInstance创建一个主窗口.

子窗口创建: WM_CREATE 就是创建的

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

直接贴出完整代码:

其中WndProc1是子窗口的消息处理函数

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static int clientCX = 0;
static int clientCY = 0;
static TCHAR *szChildClass[] = { _T("Child1"), _T("Child2"), _T("Child3"), _T("Child4") };//子窗口名字
static WNDPROC childWndProc[] = { WndProc1, WndProc2, WndProc3, WndProc4 };//子窗口的消息处理函数
static HWND hwndChild[4]; //子窗口句柄
switch (message)
{
case WM_CREATE:
{
//对四个UI窗口类进行统一初始化
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style= CS_HREDRAW | CS_VREDRAW;
wcex.cbClsExtra= 0;
wcex.cbWndExtra= 0;
wcex.hInstance= hInst;
wcex.hIcon= NULL;
wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName= NULL;
wcex.hIconSm= NULL;
for (int i = 0; i < CHILD_WND_COUNT;++i) 
{
//对不同的部分进行分别初始化
wcex.lpfnWndProc = childWndProc[i];
wcex.lpszClassName = szChildClass[i];
//注册窗口类
RegisterClassEx(&wcex);
//创建窗口  并且记录窗口句柄
hwndChild[i] = CreateWindow(
szChildClass[i],
_T(""),
WS_CHILD | WS_BORDER | WS_VISIBLE,
0, 0, 0, 0,
hWnd,
(HMENU)i,
hInst,
NULL);
}
}
break;
case WM_SIZE:
{
clientCX = LOWORD(lParam);//客户区的宽度
clientCY = HIWORD(lParam);//客户区的高度
for (int i = 0; i < CHILD_WND_COUNT; ++i)
{
// 移动窗口的位置和其大小
MoveWindow(
hwndChild[i],
(i % 2)*clientCX / 2, (i > 1)*clientCY / 2,
clientCX / 2, clientCY / 2,
TRUE
);
}
}
break;
case WM_COMMAND:
wmId    = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择: 
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO:  在此添加任意绘图代码...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK WndProc1(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static THRPARAMS thrParams;
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
{
//系统中基于对话框字体的高度
int cyChar = HIWORD(GetDialogBaseUnits());
//填充THRPARAMS结构体
thrParams.hwnd = hWnd;
thrParams.cyChar = cyChar;
//创建一个当前线程没有拥有所有权的 互斥对象
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择: 
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO:  在此添加任意绘图代码...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

1 演示创建一个Mutex互斥量

火车售票系统。

创建两个线程,演示如何进行资源的保护。两个线程竞争某个资源。

case WM_CREATE:
{
//系统中基于对话框字体的高度
int cyChar = HIWORD(GetDialogBaseUnits());
//填充THRPARAMS结构体
thrParams.hwnd = hWnd;
thrParams.cyChar = cyChar;
//创建一个当前线程没有拥有所有权的 互斥对象 
//FALSE技术递归计数器为0 线程id为0 所以是触发状态
g_hMutex = CreateMutex(NULL, FALSE, NULL);
//创建两个线程来卖火车票
HANDLE handleTicket1 = CreateThread(NULL, 0, ThrTicketProc1, &thrParams, 0, NULL);
HANDLE handleTicket2 = CreateThread(NULL, 0, ThrTicketProc2, &thrParams, 0, NULL);
/*
原因为:创建线程后返回了线程句柄,新创建的线程内核对象的使用计数是2,一个是线程本身,一个是
创建线程的线程,创建新的线程CloseHandle后,新的线程内核对象使用计数为1,当这个新线程结束运行后
内核对象的使用技术还要减1,这时内核对象的使用计数是0,则系统会自动删除新线程的内核对象,这是
正常的处理流程.
如果不调用CloseHandle()则新线程运行结束后,由于使用计数为1,所以不会删除线程的内核对象,这样
就会造成内存泄漏,当然在整个程序运行结束后,操作系统会回首这些内存,因此可以知道如果不调用
CloseHandle的话,该程序在运行阶段,会造成内存泄漏。
*/
//关闭线程句柄
CloseHandle(handleTicket1);
CloseHandle(handleTicket2);
}

//释放互斥量对象的句柄 在窗口关闭前
case WM_DESTROY:
// 关闭 互斥量句柄内存 删除
CloseHandle(g_hMutex);
PostQuitMessage(0);
break;

来看这个线程函数怎么用:

两个线程都对火车票的票数,也就是全局变量,来进行操作。

我们要避免就是同时两个线程拿到这个变量,同时进行读写操作。

导致资源,脱离控制,要做到一个线程拿到这个资源立即锁定,只有他

完成,其他线程才能进行访问。

只需要修改其中的线程名输出就可以观测了.

DWORD WINAPI ThrTicketProc1(LPVOID lp)
{
//将输入的参数 转换成结构体
PPARAMS param = static_cast<PPARAMS>(lp);
TCHAR szBuf[20] = { 0 };
HDC hdc;
//进入死循环
while (true)
{
//等待函数 无限等待,知道g_hMutex这个互斥量对象触发。
//不需要判断返回值因为参数用的INFINITE,肯定有一个线程拿到这个所有权
WaitForSingleObject(g_hMutex, INFINITE);
//如果票数大于0  g_trainTickets是一个全局变量
if (g_trainTickets > 0)
{
//在这里休眠 一下, 暂时放弃剩余的时间片
Sleep(800);
//销售火车票
// 打印表示哪个线程销售的火车票
wsprintf(szBuf, _T("线程1剩余火车票:%d"), g_trainTickets--);
// 获得绘图句柄
hdc = GetDC(param->hwnd);
//将字体绘制到子窗口中
TextOut(hdc, 0, g_iLine*param->cyChar, 
szBuf, lstrlen(szBuf));
ReleaseDC(param->hwnd,hdc);
//清空字符串
memset(szBuf, 0, sizeof(TCHAR) * 20);
//全局变量行数 
g_iLine++;
//整个子窗口 重新绘制
InvalidateRect(param->hwnd,NULL,FALSE);
//解锁释放 这个互斥量对象 使他触发
ReleaseMutex(g_hMutex);
}
else
{
//解锁释放 这个互斥量对象 使他触发
ReleaseMutex(g_hMutex);
break;
}
}
return 0;
}

我门发现井然有序,如果我们不释放Release会造成死锁,这样其他

等待的线程,或永远在等待,不会被触发。

如果我们使用Wait等待函数,那WaitForSingleObject注释掉。

两个线程同时访问一个资源,进行读写,导致资源脱离控制。

时间: 2024-12-16 13:04:26

VC++线程同步(二) Mutex互斥量的例子的相关文章

VC++多线程同步(一) Mutex互斥量

一 .同步机制的引入目的是为了解决三个主要问题 1为了控制线程之间共享资源的同步访问,保证共享资源的完整性.(比如一个线程正在更新一个数据,而另外一个线程正在读取该数据,那么就不知道该数据是新的还是旧的,为了避免这种状况的发生) 2确保线程之间的动作,以制定的次序发送,例如一个线程的触发,需要另外一个线程的结果,作为条件. 3为了控制某一个共享资源的最大访问量,例如我们同时只能处理5个客户的请求,这时候,我们需要放到队列进行等待. 二.同步概念就是等待 WIN32  提供了API 等待函数 DW

Linux程序设计学习笔记----多线程编程线程同步机制之互斥量(锁)与读写锁

互斥锁通信机制 基本原理 互斥锁以排他方式防止共享数据被并发访问,互斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个互斥锁逻辑上绑定之后,对该资源的访问操作如下: (1)在访问该资源之前需要首先申请互斥锁,如果锁处于开状态,则申请得到锁并立即上锁(关),防止其他进程访问资源,如果锁处于关,则默认阻塞等待. (2)只有锁定该互斥锁的进程才能释放该互斥锁. 互斥量类型声明为pthread_mutex_t数据类型,在<bits/pthreadtypes.h>中有具体的定义. 互斥量

线程同步方式之互斥量Mutex

互斥量和临界区非常相似,只有拥有了互斥对象的线程才可以访问共享资源,而互斥对象只有一个,因此可以保证同一时刻有且仅有一个线程可以访问共享资源,达到线程同步的目的. 互斥量相对于临界区更为高级,可以对互斥量进行命名,支持跨进程的线程同步.互斥量是调用的Win32的API对互斥锁的操作,因此在同一操作系统下不同进程可以按照互斥锁的名称共享锁. 正因为如此,互斥锁的操作会更好资源,性能上相对于临界区也有降低,在使用时还要多斟酌.对于进程内的线程同步使用临界区性能会更佳. 在.Net中使用Mutex类来

【Linux】Mutex互斥量线程同步的例子

0.互斥量  Windows下的互斥量 是个内核对象,每次WaitForSingleObject和ReleaseMutex时都会检查当前线程ID和占有互斥量的线程ID是否一致. 当多次Wait**时就要对应多次ReleaseMutex, 当ReleaseMutex过多次数时如果发现当前占有互斥量的线程ID和当前调用ReleaseMutex的线程ID不一致时仅仅返回FLASE,GetLastError返回ERROR_NOT_OWNER,没有其他副作用. 当占有mutex的线程在Release之前退

线程同步机制之互斥锁

进程间通讯介绍 1.几种进程间的通信方式 # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. # 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信. # 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问.它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源.因此,主要作为进程间以及同一进

线程同步机制之互斥锁通信机制

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <string.h> void *thread_function(void *arg); pthread_mutex_t work_mutex; #define WORK_SIZE 1024 char work_area[WORK_SIZE]; int time_to_exit=0; int main(int argc,

线程同步:何时互斥锁不够,还需要条件变量?

http://www.blogjava.net/fhtdy2004/archive/2009/07/05/285519.html 线程同步:何时互斥锁不够,还需要条件变量? 很显然,pthread中的条件变量与Java中的wait,notify类似 假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与sum的状态无关,比如只是sum++.那么只用mutex足够了.程序员只要确保每个线程操作前,取得lock,然后sum++,再unlock即可.每个

c# Thread5——线程同步之基本原子操作。Mutex互斥量的使用

之前的博文也说到了如果多线程对于访问的公共资源操作都是原子操作,那么可以避免竞争条件.关于多线程的竞争可以百度. 1.执行最基本的原子操作 c#提供了一系列供我们使用的原子操作的方法和类型,比如我们的自增和自减操作. 看代码 class Program { private static int _count = 0; static void Main(string[] args) { var thread1 = new Thread(() => { for(int i = 0; i < 100

linux 线程的同步 二 (互斥锁和条件变量)

互斥锁和条件变量 为了允许在线程或进程之间共享数据,同步时必须的,互斥锁和条件变量是同步的基本组成部分. 1.互斥锁 互斥锁是用来保护临界区资源,实际上保护的是临界区中被操纵的数据,互斥锁通常用于保护由多个线程或多进程分享的共享数据.一般是一些可供线程间使用的全局变量,来达到线程同步的目的,即保证任何时刻只有一个线程或进程在执行其中的代码.一般加锁的轮廓如下: pthread_mutex_lock() 临界区 pthread_mutex_unlock() 互斥锁API pthread_mutex