线程安全
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
1 #ifdef _WIN32 2 #include <windows.h> 3 #include <process.h> 4 #define barrier() NULL 5 class CMutex 6 { 7 public: 8 CMutex() 9 { 10 InitializeCriticalSection(&m_CriticalSetion); 11 } 12 ~CMutex() 13 { 14 DeleteCriticalSection(&m_CriticalSetion); 15 } 16 bool Lock() 17 { 18 EnterCriticalSection(&m_CriticalSetion); 19 return true; 20 } 21 bool Unlock() 22 { 23 LeaveCriticalSection(&m_CriticalSetion); 24 return true; 25 } 26 private: 27 CRITICAL_SECTION m_CriticalSetion; 28 }; 29 #else 30 #include <pthread.h> 31 #define barrier() __asm__ __volatile__("":::"memory") 32 class CMutex 33 { 34 public: 35 CMutex() 36 { 37 pthread_mutex_init(&m_Mutex, NULL); 38 } 39 ~CMutex() 40 { 41 pthread_mutex_destroy(&m_Mutex); 42 } 43 bool Lock() 44 { 45 return pthread_mutex_lock(&m_Mutex) == 0; 46 } 47 bool Unlock() 48 { 49 return pthread_mutex_unlock(&m_Mutex) == 0; 50 } 51 private: 52 pthread_mutex_t m_Mutex; 53 }; 54 #endif 55 56 template <typename T> 57 class singleton 58 { 59 public: 60 static T* GetInstance() 61 { 62 if (!m_pInst) 63 { 64 m_Mutex.Lock(); 65 if (!m_pInst) 66 { 67 T* p = new T; 68 barrier(); //barrier()执行完成之前内存被初始化 69 m_pInst = p; 70 } 71 m_Mutex.Unlock(); 72 } 73 return m_pInst; 74 } 75 protected: 76 singleton(){} 77 virtual ~singleton(){} 78 static T* m_pInst; 79 static CMutex m_Mutex; 80 81 private: 82 class C1234567 83 { 84 ~C1234567() 85 { 86 delete m_pInst; 87 m_pInst = NULL; 88 } 89 }; 90 static C1234567 m_C1234567; 91 }; 92 93 template<typename T> T* singleton<T>::m_pInst = NULL; 94 template<typename T> CMutex singleton<T>::m_Mutex; 95 template<typename T> typename singleton<T>::C1234567 singleton<T>::m_C1234567; 96 97 #include <stdio.h> 98 #include <stdlib.h> 99 #ifndef _WIN32 100 #include <unistd.h> 101 #endif 102 103 class CTest : public singleton<CTest> 104 { 105 public: 106 CTest() 107 { 108 printf("----------CTest construct----------\n"); 109 } 110 ~CTest() 111 { 112 printf("----------CTest destruct-----------\n"); 113 } 114 void print() 115 { 116 printf("CTest call print()\n"); 117 } 118 }; 119 120 // 可重入函数 121 void* work(void * arg) 122 { 123 CTest* p = CTest::GetInstance(); 124 if (p) 125 { 126 printf("CTest pointer = %p\n", p); 127 p->print(); 128 } 129 130 return NULL; 131 } 132 133 int main(int argc, char* argv[]) 134 { 135 const int MAX_COUNT = 10; 136 #ifndef _WIN32 137 pthread_t p_id[MAX_COUNT]; 138 for (int i = 0; i < MAX_COUNT; i ++) 139 { 140 if (pthread_create(&p_id[i], NULL, work, NULL) != 0) 141 { 142 perror("pthread_create"); 143 exit(0); 144 } 145 printf("create thread id = %d\n", p_id[i]); 146 } 147 for (int i = 0; i < MAX_COUNT; i ++) 148 pthread_join(p_id[i], NULL); 149 #else 150 HANDLE hThread[MAX_COUNT]; 151 for (int i = 0; i < MAX_COUNT; i++) 152 { 153 hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)work, NULL, 0, NULL); 154 printf("create thread id = %d\n", hThread[i]); 155 } 156 WaitForMultipleObjects(MAX_COUNT, hThread, TRUE, INFINITE); 157 #endif 158 159 return 0; 160 }