C++拾遗--多线程:原子操作解决线程冲突

C++拾遗--多线程:原子操作解决线程冲突

前言

在多线程中操作全局变量一般都会引起线程冲突,为了解决线程冲突,引入原子操作。

正文

1.线程冲突

#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <Windows.h>
int g_count = 0;
void count(void *p)
{
	Sleep(100);    //do some work
	//每个线程把g_count加1共10次
	for (int i = 0; i < 10; i++)
	{
		g_count++;
	}
	Sleep(100);   //do some work
}
int main(void)
{
	printf("******多线程访问全局变量演示***by David***\n");
	//共创建10个线程
	HANDLE handles[10];
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			handles[j] = _beginthread(count, 0, NULL);
		}
		WaitForMultipleObjects(10, handles, 1, INFINITE);
		printf("%d time g_count = %d\n", i, g_count);
		//重置
		g_count = 0;
	}
	getchar();
	return 0;
}

运行

理论上,g_count的最后结果应该是100,可事实却并非如此,不但结果不一定是100,而且每次的结果还很可能不一样。原因是,多个线程对同一个全局变量进行访问时,特别是在进行修改操作,会引起冲突。详细解释:

设置断点,查看反汇编

g_count++;被分为三步操作:

1.把g_count的内容从内存中移动到寄存器eax

2.把寄存器eax加1

3.把寄存器eax中的内容移动到内存g_count的地址

三步以后,g_count的值被顺利加1。

cpu执行的时间片内包含多条指令,每条指令执行期间不会被打断,但如果一个操作包含多条指令,则很有可能该操作会被打断。g_count++;就是这样的操作。

g_count被顺利加到100的前提:每次加1,都建立在上一次加1顺利完成的基础上。也就是说,如果上一次加1被打断,这一次的加1就得不到上一次加1的累积效果。自然,最后的结果,多半会小于100。

2.原子操作

所谓原子操作,是指不会被线程调度机制打断的操作,操作一旦开始,就得执行到结束为止。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。原子操作一般靠底层汇编实现。

在头文件winnt.h中提供了很多的原子操作函数,它们使用自加锁的方式,保证操作的原子性,如自增操作

InterlockedIncrement,

函数原型

LONG CDECL_NON_WVMPURE InterlockedIncrement(

_Inout_ _Interlocked_operand_ LONG volatile *Addend

);

其它相关操作,请自行查看头文件。

使用该函数,我们修改线程函数count。修改很简单,只需把g_count++改为InterlockedIncrement((LONG)&g_count);即可。

运行如下

显然,在原子操作下,我们肯定是可以得到正确结果的。

本专栏目录

所有内容的目录

时间: 2024-08-05 19:36:04

C++拾遗--多线程:原子操作解决线程冲突的相关文章

java 22 - 12 多线程之解决线程安全问题的实现方式1

从上一章知道了多线程存在着线程安全问题,那么,如何解决线程安全问题呢? 导致出现问题的原因: A:是否是多线程环境 B:是否有共享数据 C:是否有多条语句操作共享数据 上一章的程序,上面那3条都具备,所以肯定出问题. 如何解决问题: 原因A.B肯定不能改变,所以只能改变原因C 解决问题思路: 如果把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行这个整体的时候,别的线程不能执行. 这时候就用到了java提供的:同步机制 同步代码块: synchronized(对象){  需要同步的代码

单例模式,解决线程冲突

/** * 单例模式的使用 * * 单例创建用户服务对象 没必要给每个用户都创建一个 *  * 单例 :1 构造方法私有化 2 创建一个私有的静态变量 3 公共的静态方法 当做入口 *  * @param user */ /* * 第一种单例模式 */ // 问题 : 预先加载,没有手动实例化变量的时候 已经实例化了变量// 当你要使用对象的时候,只是把这个变量给你 // 1 构造方法私有化 外界不能直接访问private UserService(){}// 2 创建一个私有的静态变量(常量)p

C++拾遗--多线程:临界区解决子线程的互斥

C++拾遗--多线程:临界区解决子线程的互斥 前言 为了解决子线程的互斥问题,windows系统提出了关键段或临界区(CRITICAL_SECTION)的概念.它一共有四个共两对操作:初始化.销毁,进入.离开.它们定义在头文件synchapi.h中. 1.初始化变量 VOID WINAPI InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); 2.销毁变量 VOID WINAPI DeleteCriticalSect

C++拾遗--多线程:主线程与子线程的同步

C++拾遗--多线程:主线程与子线程的同步 前言 在多线程编程时,有时是需要要求主线程与子线程同步的. 正文 程序演示 下面的一个例子,演示了主线程与子线程之间的同步问题. 程序描述: 在主线程中,有一整型变量count,初始化为0.主线程把count的地址传递给开启的子线程,子线程打印获取的值,随后主线程递增count的值,再次开启另一个子线程,传递count的地址-- #include <stdio.h> #include <stdlib.h> #include <pro

java——多线程的实现方式、两种办法解决线程赛跑

多线程的实现方式:demo1.demo2 demo1:继承Thread类,重写run()方法 package thread_test; public class ThreadDemo1 extends Thread { ThreadDemo1(){ } ThreadDemo1(String szName){ super(szName); } //重载run函数 public void run() { for(int count = 1 , row = 1 ; row < 10 ; row ++

.NET面试题解析(07)-多线程编程与线程同步

系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实是很多的,比如多线程编程.线程上下文.异步编程.线程同步构造.GUI的跨线程访问等等,本文只是从常见面试题的角度(也是开发过程中常用)去深入浅出线程相关的知识.如果想要系统的学习多线程,没有捷径的,也不要偷懒,还是去看专业书籍的比较好. 常见面试题目: 1. 描述线程与进程的区别? 2. 为什么GUI不支持跨线程访问控件?一般如何解决这个问题? 3. 简述后台线程和前台线程的区别? 4. 说说常

Java多线程学习之线程的同步

多线程编程要解决的一个基本问题是:共享资源的竞争.而基本上使用并发模式在解决这个问题都采用序列化访问共享资源的方法.基本原理就是当共享资源被一个任务使用时,在其上加锁,其他任务在资源被解锁之前,无法访问它.在任务对其解锁后,另一个任务就可以锁定并使用它.下面看看Java支持的线程同步机制. 1.synchronized关键字 synchronized关键字即可应用于对象相关的同步,也可用于类层次的同步(static属性): 对象上应用synchronized可以实现对象方法的同步和代码块的同步.

Spring学习11- Spring使用ThreadLocal解决线程安全问题

ThreadLocal是什么      早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地编写出优美的多线程程序. ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”.其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些.      当使用ThreadLoca

转载 多线程开发时线程局部变量的使用

多线程开发时线程局部变量的使用 http://blog.csdn.net/zsxxsz/article/details/6284759 2011-03-28 22:37197人阅读评论(0)收藏举报 一.概述 现在多核时代多线程开发越来越重要了,多线程相比于多进程有诸多优势(当然也有诸多劣势).在早期C的库中,有许多函数是线程不安全的,因为内 部用到了静态变量,比如:char *strtok(char *s, const char *delim); 该函数内部就有一个静态指针,如果多个线程同时调