經過共享內存通訊是最快的,不過既然是共享資源,那麼就必需要有同步機制。segmentfault
建立共享內存有兩種方式shm和mmap的方式。app
shm的建立要確保原子性的話,能夠經過重命名來作。函數
http://www.javashuo.com/article/p-ktybynmz-km.htmlspa
1 char* SharedMemory::CreateMapping(const std::string file_name, unsigned mapping_size, bool &is_new) { 2 char* mapping = (char*)MAP_FAILED; 3 int fd = -1; 4 fd = open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0666); // 同步O_EXCL 5 if (fd == -1) { 6 fd = open(file_name.c_str(), O_RDWR, 0666); 7 if (fd < 0) { 8 return mapping; 9 } 10 } 11 12 struct stat file_stat; 13 if(fstat(fd, &file_stat)== -1) { 14 close(fd); 15 return mapping; 16 } 17 int file_size = file_stat.st_size; 18 is_new = false; 19 if (file_size == 0) { 20 file_size = mapping_size; 21 ftruncate(fd, file_size); 22 is_new = true; 23 } 24 mapping = (char*)mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 25 if (is_new) { 26 memset(mapping, 0, sizeof(char) * file_size); 27 } 28 close(fd); 29 return mapping; 30 }
這裏用O_CREAT | O_EXCL來確保只建立一次文件,若是建立失敗就以rw的方式來打開。操作系統
跨進程的同步機制,根據APUE 15.9節提到的,能夠有三種方式,帶undo的信號量、記錄鎖、互斥量。pthread帶的跨進程互斥量須要高版本支持。.net
1 bool SharedMemory::Init() { 2 bool is_new = false; 3 mutex_ = (pthread_mutex_t *)CreateMapping(file_name_ + ".lock", sizeof(pthread_mutex_t), is_new); 4 if (mutex_ == MAP_FAILED) { 5 return false; 6 } 7 if (is_new) { 8 InitLock(); 9 } 10 is_init_ = true; 11 return true; 12 } 13 14 void SharedMemory::InitLock() { 15 pthread_mutexattr_t attr; 16 pthread_mutexattr_init(&attr); //~necessary, or weird EINVAL error occurs when operating on the mutex 17 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); 18 pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST); 19 pthread_mutex_init(mutex_, &attr); 20 } 21 22 void SharedMemory::Lock() { 23 if (!is_init_) { 24 return; 25 } 26 while (EOWNERDEAD == pthread_mutex_lock(mutex_)) { 27 pthread_mutex_consistent(mutex_); 28 pthread_mutex_unlock(mutex_); 29 } 30 } 31 32 void SharedMemory::Unlock() { 33 if (!is_init_) { 34 return; 35 } 36 pthread_mutex_unlock(mutex_); 37 }
pthread_mutex_consistent這個函數有版本限制。線程
若是持有 mutex 的線程退出,另一個線程在 pthread_mutex_lock 的時候會返回 EOWNERDEAD。這時候你須要調用 pthread_mutex_consistent 函數來清除這種狀態,不然後果自負。code
http://www.javashuo.com/article/p-ktybynmz-km.htmlblog
pthread_mutexattr_setpshared配合PTHREAD_PROCESS_SHARED能夠建立跨進程的mutex,可是必需保證mutex所在的內存區域能夠被每一個進程訪問,也就是說必需被建立在進程間共享的內存區域中,好比mmap建立的共享內存。進程
https://segmentfault.com/q/1010000000628904
記錄鎖的功能:當一個進程正在讀或修改文件的某個部分是,它能夠阻止其餘進程修改同一文件區。
記錄鎖是更經常使用的方式。由於它沒有版本限制,進程退出時會自動釋放鎖。
1 void SharedMemory::InitLock(short type) { 2 if (lock_fd_ < 0) { 3 return; 4 } 5 struct flock lock; 6 lock.l_type = type; 7 lock.l_whence = SEEK_SET; 8 lock.l_start = 0; 9 lock.l_len = 0; 10 int ret = fcntl(lock_fd_, F_SETLKW, &lock); 11 //printf("InitLock %d \n", ret); 12 } 13 14 void SharedMemory::LockWrite() { 15 if (!is_init_) { 16 return; 17 } 18 19 InitLock(F_WRLCK); 20 } 21 22 void SharedMemory::LockRead() { 23 if (!is_init_) { 24 return; 25 } 26 27 InitLock(F_RDLCK); 28 } 29 30 void SharedMemory::Unlock() { 31 if (!is_init_) { 32 return; 33 } 34 InitLock(F_UNLCK); 35 }