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

场景:

1.  在多线程程序里,临界区是最常见的同步访问共享资源的最简单的解决方案.

2. pthread是跨平台的线程模型,那么它和本地的线程模型的临界区编程有什么区别呢?

临界区:

临界区是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。这是让若干代码能够"以原子操作方式"来使用资源的一种方法。

所谓原子(atomic)操作方式,是指这段代码知道没有别的线程要访问这个资源.

说明:

1.  MacOSX,Windows有自己的线程模型, pthread可以说是跨平台的线程编程模型解决方案,当然对pthread不熟悉的也可以使用本地线程模型,

其实pthread的win32版本也是基于本地线程模型的, pthread-win32的mutex是用户态的临界区实现,和win32的内核对象Mutex不同.

2. POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API。在类Unix操作系统(Unix、Linux、Mac OS X等)中,

都使用Pthreads作为操作系统的线程。Windows操作系统也有其移植版pthreads-win32。

http://sourceware.org/pthreads-win32/

3. 临界区属于用户模式对象,实际上这种说法并不完全正确。如果一个线程试图进入另一个线程所拥有的临界区,那么这个线程就会被置为等待状态。

而进入等待状态的唯一方法是使用线程从用户模式转入内核模式,所以追求高效的实现临界区时就是想办法避免进入等待状态下的内核模式.

例子:

test_user_sync.cpp

// test_user_sync.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <Windows.h>
#include "pthread.h"
#include <iostream>

using namespace std;

static pthread_mutex_t cs_mutex =  NULL;
static pthread_barrier_t barrier = NULL;

static CRITICAL_SECTION cs;

static int32_t gCount = 0;
static int32_t gExecuteCount = 0;
static const int kThreadNum = 10;
static const int kLoopNum = 100;

void sync_func()
{
	++gExecuteCount;
	cout << "sync_func CurrentThreadID: " << GetCurrentThreadId()
		 << " gExecuteCount: " << gExecuteCount << endl;
	//1.计数器递增
	//1.断言只有一个线程访问这段代码.
	assert(gCount == 0);
	++gCount;
	assert(gCount == 1);

	//1.挂起0.1秒钟,模拟计算耗时.
	Sleep(100);
	//1.离开函数,计数器递减
	assert(gCount == 1);
	--gCount;
	assert(gCount == 0);
}

void* StartPthread(void* data)
{
	for(int i = 0; i < kLoopNum; ++i)
	{
		pthread_mutex_lock( &cs_mutex );
		sync_func();
		pthread_mutex_unlock( &cs_mutex );
		//1.挂起0.1秒,让其他线程也有机会执行.
		Sleep(100);
	}
    pthread_barrier_wait(&barrier);

	return NULL;
}

void TestPthreadCriticalSection()
{
	gExecuteCount = 0;
	pthread_mutex_init(&cs_mutex,NULL);
	//1.创建10个线程.
	//1.包括当前线程+1
	pthread_barrier_init(&barrier,NULL, kThreadNum + 1);
	for(int i = 0; i< kThreadNum; ++i)
	{
		pthread_t t;
		pthread_create(&t,NULL,StartPthread,NULL);
		pthread_detach(t);
	}
	pthread_mutex_destroy(&cs_mutex);

	//1.等待其他线程执行完.
	pthread_barrier_wait(&barrier);
	assert(kThreadNum*kLoopNum == gExecuteCount);
}

DWORD WINAPI StartWin32Thread(PVOID pvParam)
{
	for(int i = 0; i < kLoopNum; ++i)
	{
		EnterCriticalSection(&cs);
		sync_func();
		LeaveCriticalSection(&cs);
		//1.挂起0.1秒,让其他线程也有机会执行.
		Sleep(100);
	}
	return 0;
}

void TestWin32CriticalSection()
{
	gExecuteCount = 0;

	InitializeCriticalSection(&cs);

	HANDLE hThreads[kThreadNum];
    for(int i = 0; i< kThreadNum; ++i)
	{
		DWORD dwThreadID;
		hThreads[i] = CreateThread(NULL,0,StartWin32Thread,NULL,0,&dwThreadID);
	}
	DWORD rc = WaitForMultipleObjects(kThreadNum, hThreads, TRUE, INFINITE);
	assert(rc == WAIT_OBJECT_0);
	for(int i = 0; i< kThreadNum; ++i)
	{
		CloseHandle(hThreads[i]);
	}

	DeleteCriticalSection(&cs);
}

int _tmain(int argc, _TCHAR* argv[])
{
	TestWin32CriticalSection();
	system("pause");

	TestPthreadCriticalSection();
	system("pause");

	return 0;
}

输出:

项目下载地址:

参考:

http://blog.sina.com.cn/s/blog_4d253de30100ymov.html

http://en.wikipedia.org/wiki/Critical_section

http://blog.csdn.net/wind19/article/details/7520860

http://www.cppblog.com/sixinquan/archive/2010/02/22/108229.html

http://blog.csdn.net/qq405180763/article/details/23919191

《Windows核心编程 第4版》

时间: 2024-08-15 20:47:26

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

一个简单的线程锁------pthread和win32的临界区(Critical Section)

临界区: 临界区是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权.这是让若干代码能够"以原子操作方式"来使用资源的一种方法. 所谓原子(atomic)操作方式,是指这段代码知道没有别的线程要访问这个资源. 说明: 1.  MacOSX,Windows有自己的线程模型, pthread可以说是跨平台的线程编程模型解决方案,当然对pthread不熟悉的也可以使用本地线程模型, 其实pthread的win32版本也是基于本地线程模型的, pthread-win32的mutex

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

场景: 1. 多线程编程时,有时候需要统计某个变量或对象的创建个数或者是根据某个变量值来判断是否需要继续执行下去,这时候互锁函数是比较高效的方案之一了. 说明: 1.原子访问:(互锁函数族) -- 原子访问,指线程在访问资源时能够确保所有其他线程都不在同一时间内访问相同的资源. -- 调用一个互锁函数通常只需要执行几个CPU周期(通常小于50),并且不需要从用户模式转换为内核模式(通常这需要1000个CPU周期). -- 互锁函数是CPU硬件支持的,如果是x86处理器,互锁函数会向总线发出一个硬

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)

第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 . 多线程共享数据 在多线程操作中, 多个线程有可能同时处理同一个资源, 这就是多线程中的共享数据. 举个不太恰当的例子简单理解一下,图中是小新家的厕所茅坑,但是家里只有一个那这就是一个"资源",那么家里的所有人都共享这同一个"资源",也就是所谓的多线程共享数据 可以明显的看出多线程共享数据带来的问题,就是会造成数据的不确定性!就好比小新正在上着厕所,此时小新爸爸来了, 此时相当于一个资源两个人在