原子操作_C/C++_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > C/C++ > 原子操作

原子操作

 2018/5/15 21:11:56  tcspecial  程序员俱乐部  我要评论(0)
  • 摘要:一.Javavolatilevolatile关键字可保证变量可见性,但是无法保证原子性,下面演示多线程修改共享变量Count场景。/***共享变量在多线程下修改测试*/publicclassNonAtomicTestextendsThread{publicstaticvolatileintcount=0;publicvoidincrease(){count++;}publicvoidrun(){for(inti=0;i<10000;i++){increase();}
  • 标签:操作

?

一. Java volatile

volatile关键字可保证变量可见性,但是无法保证原子性,下面演示多线程修改共享变量Count场景。

??

class="java">/**
 * 共享变量在多线程下修改测试
 */
public class NonAtomicTest extends Thread {
	public static volatile int count = 0;
	
	public void increase(){
		count++;
	}
	
	public void run(){
		for(int i=0; i<10000; i++){
			increase();
		}
	}
	
	// main
	public static void main(String[] args) {
		Thread[] ths = new NonAtomicTest[20];
		
		for(int i=0; i<ths.length; i++){
			ths[i] = new NonAtomicTest();
			ths[i].start();
		}
		
		while(Thread.activeCount() > 1){
			Thread.yield();
		}
		
		System.out.println("Val: "+ count);
	}
}

?

执行上述代码,发现每次执行count的值都不同,均小于200000。原因count++非原子操作,字节码执行过程:

GETSTATIC count 	// 从内存加载count到栈
ICONST_1			// 从栈中读取count值
IADD				// 执行加法
PUTSTATIC count 	// 将执行结果存储至内存

?

对于上述问题,可对线程执行体加锁同步访问,但是加锁开销较大。Java中提供了AutomicInteger, AutomicLong 等原子操作类来处理上述问题,也是目前比较流行的无锁编程。原子操作由底层硬件 cmpxchg 指令支持,Linux 内核大量使用该指令。C++11也单独提供了原子类。

?

二. C++ 无锁编程

Linux下也提供原子操作API,C++11 std::aomic<T>模板均可进行无锁编程。

#include <iostream>
#include <vector>
#include <thread>
#include <atomic>
#include <mutex>

/// main
int main(int argc, char **argv)
{
	static volatile int Count = 0;
	std::mutex mutex;

	// 方案一:互斥锁
	auto fn1 = [&mutex, &Count]
	{
		for (int i=0; i<10000; i++)
		{
			std::lock_guard<std::mutex> lock(mutex);
			Count++;
		}
	};
	
	// 方案二:原子操作接口
	auto fn2 = [&Count]
	{
		for (int i=0; i<10000; i++)
		{
			__sync_fetch_and_add(&Count, 1);
			//__atomic_add_fetch(&Count, 1, __ATOMIC_SEQ_CST);
		}
	};
	
	static std::atomic<int> Count(0);
	
	// 方案三:原子类
	auto fn3 = [&Count]
	{
		for (int i=0; i<10000; i++)
		{
			std::atomic_fetch_add(&Count, 1);
		}
	};
	
	///
	std::vector<std::thread> threads;
	
	// 启动20个线程
	for(int i=0; i<20; i++)
	{
		threads.push_back(std::thread(fn2));
	}

	// 等待线程执行完成
	for (auto &th : threads)
	{
		th.join();
	}

	std::cout << "Val: " << Count << std::endl;	
	return 0;
}

?

g++ -o test test.c -std=c++11 -lpthread

上述三种方案均可打印200000

?

?

?

??

?

上一篇: 像鸟一样思考更好的并行编程 下一篇: 没有下一篇了!
发表评论
用户名: 匿名