首页 > 代码库 > 线程安全

线程安全

1,原子操作

通常cpu的最小执行单元是一条指令,是不会被打断的。我们把单条指令的操作成为是原子的,但是像自增或自减这样的操作由几条指令组成,是非原子操作。window提供了一些专门的原子操作的API:

2,同步与锁

a,二元信号量(线程间共享)

b,互斥量(mutex)

c,临界区(Critical Section)

d,读写锁(read-write lock)

e,条件变量

3,可重入函数

一个函数被重入有两种情况:

a,多个线程同时执行这个函数

b,函数自身(可能进过多层调用)调用自身

可重入函数是线程并发安全的强力保障,多线程环境下可以放心使用

4,线程安全

没有绝对安全的多线程程序

a,过度优化,编译器对代码执行优化导致非线程安全,如编译器为提高对变量x的访问速度,将其放入寄存器。可以使用volatile修饰

b,CPU动态调度,导致乱序执行

5,线程安全的singleton

/*************************************************************************
    > File Name: singleton.cpp
    > Author: xlplbo
    > Mail: booxlp@gmail.com
    > Created Time: Wed 29 Oct 2014 07:01:29 AM PDT
 ************************************************************************/

#ifdef _WIN32
#include <windows.h>
#include <process.h>
#define barrier() NULL
class CMutex
{
public:
	CMutex()
	{
		InitializeCriticalSection(&m_CriticalSetion);
	}
	~CMutex()
	{
		DeleteCriticalSection(&m_CriticalSetion);
	}
	bool Lock()
	{
		EnterCriticalSection(&m_CriticalSetion);
		return true;
	}
	bool Unlock()
	{
		LeaveCriticalSection(&m_CriticalSetion);
		return true;
	}
private:
	CRITICAL_SECTION m_CriticalSetion;
};
#else
#include <pthread.h>
#define barrier() __asm__ __volatile__("":::"memory")
class CMutex
{
public:
	CMutex()
	{
		pthread_mutex_init(&m_Mutex, NULL);
	}
	~CMutex()
	{
		pthread_mutex_destroy(&m_Mutex);
	}
	bool Lock()
	{
		return pthread_mutex_lock(&m_Mutex) == 0;
	}
	bool Unlock()
	{
		return pthread_mutex_unlock(&m_Mutex) == 0;
	}
private:
	pthread_mutex_t m_Mutex;
};
#endif

template <typename T>
class singleton
{
public:
	static T* GetInstance()
	{
		if (!m_pInst)
		{
			m_Mutex.Lock();
			if (!m_pInst)
			{
				T* p = new T;
				barrier(); //barrier()执行完成之前内存被初始化
				m_pInst = p;
			}
			m_Mutex.Unlock();
		}
		return m_pInst;
	}
	~singleton()
	{
		delete m_pInst;
		m_pInst = NULL;
	}
private:
	singleton();
	static T* m_pInst;
	static CMutex m_Mutex;
};

template<typename T> T* singleton<T>::m_pInst = NULL;
template<typename T> CMutex singleton<T>::m_Mutex;

#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif

class CTest
{
public:
	void print()
	{
		printf("CTest call print()\n");
	}
};

// 可重入函数
void* work(void * arg)
{
	CTest* p = (CTest*)singleton<CTest>::GetInstance();
	if (p)
	{
		printf("CTest pointer = %p\n", p);
		p->print();
	}

#ifndef _WIN32
	sleep(5);
#else
	Sleep(5000);
#endif

	return NULL;
}

int main(int argc, char* argv[])
{
	const int MAX_COUNT = 10;

#ifndef _WIN32
	pthread_t p_id[MAX_COUNT];
	for (int i = 0; i < MAX_COUNT; i ++)
	{
		if (pthread_create(&p_id[i], NULL, work, NULL) != 0)
		{
			perror("pthread_create");
			exit(0);
		}
		printf("create thread id = %d\n", p_id[i]);
	}
	for (int i = 0; i < MAX_COUNT; i ++)
		pthread_join(p_id[i], NULL);
#else
	HANDLE hThread[MAX_COUNT];
	for (int i = 0; i < MAX_COUNT; i++)
	{
		hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)work, NULL, 0, NULL);
		printf("create thread id = %d\n", hThread[i]);
	}
	WaitForMultipleObjects(MAX_COUNT, hThread, TRUE, INFINITE);
#endif

	return 1;
}




线程安全