[并发并行]_[线程同步]_[Windows用户态下的原子访问的互锁函数]

场景:

1. 多线程编程时,有时候需要统计某个变量或对象的创建个数或者是根据某个变量值来判断是否需要继续执行下去,这时候互锁函数是比较高效的方案之一了。

说明:

1.原子访问:(互锁函数族)

-- 原子访问,指线程在访问资源时能够确保所有其他线程都不在同一时间内访问相同的资源.

-- 调用一个互锁函数通常只需要执行几个CPU周期(通常小于50),并且不需要从用户模式转换为内核模式(通常这需要1000个CPU周期).

-- 互锁函数是CPU硬件支持的,如果是x86处理器,互锁函数会向总线发出一个硬件信号,防止其他处理器访问同一个内存地址.

-- 无论编译器怎么生成代码,无论计算机中安装了多少个处理器,都能那个保证以原子操作方式来修改一个值.

-- 必须保证传递给这个函数的变量地址正确的对齐,否则这些函数就会运行失败.

(1) CPU处理准确对齐的数据时,它的运行效率最高.在用数据的大小对内存地址取模,结果为0时,数据是对齐的。例如,WORD类型的值

应该总是从能够被2除尽的地址开始,而DWORD类型的值则应该总是从能够被4除尽的地址开始.

test_interlock.cpp

// test_interlock.cpp : 定义控制台应用程序的入口点。
// 原子访问: 互锁的函数家族.

#include "stdafx.h"
#include <Windows.h>
#include <stdint.h>
#include <assert.h>
#include <iostream>

using namespace std;

static int32_t gCount = 0;
static int32_t gExecuteCount = 0;
static const int kThreadNum = 10;
static const int kLoopNum = 1000;
static uint32_t setted = 0;

#define APR_ALIGN(size, boundary) 	(((size) + ((boundary) - 1)) & ~((boundary) - 1))  

DWORD WINAPI ThreadFunc(PVOID pvParam)
{
	long* g_x = (long*)pvParam;
	for(int i = 0; i< kLoopNum; ++i)
	{
		//cout << "sync_func CurrentThreadID: " << GetCurrentThreadId() << endl;
		InterlockedExchangeAdd(g_x,1);
		InterlockedExchange(&setted,i%2);
		//1.让其他线程也有机会执行.
		Sleep(10);
	}
	return 0;
}

void TestInterlockedExchangeAdd()
{
	HANDLE hThreads[kThreadNum];
	//《Windows核心编程》说地址要对齐,虽然x86会额外做对齐的指令操作.
	// 但是能自己对齐还是自己对齐吧.比如AMD cpu不对齐可能会出现问题.
	long g_x = 0;
	for(int i = 0; i< kThreadNum; ++i)
	{
		DWORD dwThreadID;
		hThreads[i] = CreateThread(NULL,0,ThreadFunc,&g_x,0,&dwThreadID);
	}
	DWORD rc = WaitForMultipleObjects(kThreadNum, hThreads, TRUE, INFINITE);
	assert(rc == WAIT_OBJECT_0);
	for(int i = 0; i< kThreadNum; ++i)
	{
		CloseHandle(hThreads[i]);
	}
	assert(g_x == 10000);
	assert(setted == 1);
}

int _tmain(int argc, _TCHAR* argv[])
{
	TestInterlockedExchangeAdd();
	return 0;
}
时间: 2024-12-25 11:56:07

[并发并行]_[线程同步]_[Windows用户态下的原子访问的互锁函数]的相关文章

[并发并行]_[线程同步]_[pthread和win32的临界区(Critical Section)比较]

场景: 1.  在多线程程序里,临界区是最常见的同步访问共享资源的最简单的解决方案. 2. pthread是跨平台的线程模型,那么它和本地的线程模型的临界区编程有什么区别呢? 临界区: 临界区是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权.这是让若干代码能够"以原子操作方式"来使用资源的一种方法. 所谓原子(atomic)操作方式,是指这段代码知道没有别的线程要访问这个资源. 说明: 1.  MacOSX,Windows有自己的线程模型, pthread可以说是跨平台

C#并行编程-线程同步原语

原文:C#并行编程-线程同步原语 菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 背景 有时候必须访问变量.实例.方法.属性或者结构体,而这些并没有准备好用于并发访问,或者有时候需要执行部分代码,而这些代码必须单独运行,这是不得不通过将任务分解的方式让它们独立运行. 当任务和线程要访问共享的数据和资源的时候,您必须添加显示的同步,或者使用原子操作或锁. 之前的.NET Framework提供了昂贵的锁机制以及遗留的多线程模型,新的数据结构允许细粒度的并发和并行化,

JAVA并发编程4_线程同步之volatile关键字

上一篇博客JAVA并发编程3_线程同步之synchronized关键字中讲解了JAVA中保证线程同步的关键字synchronized,其实JAVA里面还有个较弱的同步机制volatile.volatile关键字是JAVA中的轻量级的同步机制,用来将变量的更新操作同步到其他线程.从内存可见性的角度来说,写入volatile变量相当于退出同步代码块,读取volatile变量相当于进入同步代码块. 旧的内存模型:保证读写volatile都直接发生在main memory中. 在新的内存模型下(1.5)

list.h在用户态下的应用

一.背景 list.h文件位于linux/include下,内核中链表的操作函数都在其中.它有许多关于链表的操作函数,所以我们可以尝试将list.h拉到用户态中来使用,这样,我们在用户态中若要用到链表就可以直接调用其中已经实现好的函数了.我这里将拉到用户态的经过"改造"后的list.h文件代码列出,然后举一个简单的例子来应用这个头文件.当然,list.h中的函数非常多,应用也应该很广泛,我这里只是简单的示例其中较简单的几个函数. 二.用户态下的list.h /* * @file lis

第9章 线程编程(4)_线程同步1:互斥锁

5. 线程的互斥和同步 5.1 同步和互斥的概念 (1)线程同步:是一个宏观概念,在微观上包含线程的相互排斥和线程的先后执行的约束问题.解决同步方式一般采用条件变量和信号量. (2)线程互斥:线程执行的相互排斥(注意,它不关心线程间执行的先后顺序!).解决互斥一般使用互斥锁.读写锁和信号量. [编程实验]银行ATM(线程不安全的例子) //account.h #ifndef __ACCOUNT_H__ #define __ACCOUNT_H__ typedef struct { int code

C#并行编程-线程同步原语(Barrier,CountdownEvent,ManualResetEventSlim,SemaphoreSlim,SpinLock,SpinWait,Monitor,volatile)

菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 背景 有时候必须访问变量.实例.方法.属性或者结构体,而这些并没有准备好用于并发访问,或者有时候需要执行部分代码,而这些代码必须单独运行,这是不得不通过将任务分解的方式让它们独立运行. 当任务和线程要访问共享的数据和资源的时候,您必须添加显示的同步,或者使用原子操作或锁. 之前的.NET Framework提供了昂贵的锁机制以及遗留的多线程模型,新的数据结构允许细粒度的并发和并行化,并且降低一定必要的开销,这些数据结

JAVA并发编程3_线程同步之synchronized关键字

在上一篇博客里讲解了JAVA的线程的内存模型,见:JAVA并发编程2_线程安全&内存模型,接着上一篇提到的问题解决多线程共享资源的情况下的线程安全问题. 不安全线程分析 public class Test implements Runnable { private int i = 0; private int getNext() { return i++; } @Override public void run() { // synchronized while (true) { synchro

JAVA 并发编程-传统线程同步通信技术(四)

首先介绍几个概念: wait()方法 wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法. 当前的线程必须拥有当前对象的monitor,也即lock,就是锁. 线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行. 要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或s

【好程序员训练营】-Java多线程与并发(二)之线程同步

android培训--我的java笔记,期待与您交流! 线程同步 1 . 多线程共享数据 在多线程操作中, 多个线程有可能同时处理同一个资源, 这就是多线程中的共享数据. 举个不太恰当的例子简单理解一下,图中是小新家的厕所茅坑,但是家里只有一个那这就是一个"资源",那么家里的所有人都共享这同一个"资源",也就是所谓的多线程共享数据 可以明显的看出多线程共享数据带来的问题,就是会造成数据的不确定性!就好比小新正在上着厕所,此时小新爸爸来了, 此时相当于一个资源两个人在