前言
对于进程间的同步知识,之前觉的自己什么都了解一些,在使用的时候觉的什么都不确定。所以决定好好温故一下。
互斥量和条件变量出自Posix.1线程标准,一般用于线程间的同步,但是它也可以用作进程间的同步。
是否能用于进程间同步在posix中是一个选项,不是必然的要求。可以通过如下代码测试是否支持进程间同步
#ifdef _POSIX_THREAD_PROCESS_SHARED
//支持进程间同步
#endif
一、互斥量和条件变量的初始化
互斥量和条件变量的结构体如下:
pthread_mutex_t mutex;
pthread_cond_t cond;
它们的初始化步骤基本一样,都分为静态初始化和动态初始化。在线程间同步一般用静态初始化,在进程间同步用动态初始化。
//静态初始化
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//动态初始化
pthread_mutex_init();
pthread_cond_init();
要想用作进程间同步,需要将这个两个东东放在进程都能访问的公共区域,所以需要放在共享内存区。这样多个进程能够访问,起到同步共享内存的作用。
并且pthread_mutex_t 和 pthread_cond_t是有属性的,默认属性是用作线程的,用于进程间需要设置它们的属性为共享,代码片段如下:
pthread_mutex_t mutex;
pthread_cond_t cond;
void Init(){
//定义条件变量属性,并初始化
pthread_condattr_t condattr;
pthread_condattr_init(&condattr);
//定义互斥量属性,并初始化
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init(&mutexattr);
//判断系统是否支持用于进程间同步,并且设置它们的属性为进程间使用
#ifdef _POSIX_THREAD_PROCESS_SHARED
pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED);
#else
//ERROR does not support PTHREAD_PROCESS_SHARED
#endif
//使用已经初始化好的属性变量来初始化互斥量和条件变量
pthread_cond_init(&cond, &condattr);
pthread_mutex_init(&mutex, &mutexattr);
//设置完成后属性变量没用了,销毁
pthread_mutexattr_destroy(&mutexattr);
pthread_condattr_destroy(&condattr);
}
二、操作步骤
操作函数的定义如下
#include <pthread.h>
pthread_mutex_lock(pthread_mutex_t*);
pthread_mutex_trylock(pthread_mutex_t*);
pthread_mutex_timedlock(pthread_mutex_t*, const struct timespec *);
pthread_mutex_unlock(pthread_mutex_t*);
pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*);
pthread_cond_signal(pthread_cond_t*);
pthread_cond_broadcast(pthread_cond_t *);
pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, const struct timespec *);
一般的生产者消费者流程如下:
////>> 生产者
lock
//临界区,操作数据
unlock
signal/broadcast
////>> 消费者
lock
wait
//临界区,操作数据
unlock
如果涉及多生产者消费者需要考虑其他的东西。例如在多生产者单消费者中,如果数据没有被消费,那么下一个生产者生产的数据是否覆盖共享区的数据。
三、代码小例子
demo程序是在共享内存中使用条件变量和互斥量来同步两个进程:
生产者进程 a.cpp
#include "type.h"
#include <iostream>
#include <string>
#include "string.h"
int main(int argc, char *argv[])
{
if(shm_unlink(key.data()) == -1){
if(errno == ENOENT)
std::cout << "not have shm!" << std::endl;
}
int fd = shm_open(key.data(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
if(fd == -1){
perror("open shm error");
return -1;
}
struct stat sb;
fstat(fd, &sb);
std::cout << sb.st_size << std::endl;
if(sb.st_size != MEM_SIZE)
ftruncate(fd, MEM_SIZE);
void *handle = mmap(nullptr, MEM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(handle == MAP_FAILED){
perror("mmap error : ");
return -2;
}
close(fd);
SyncLock *g_mutex = reinterpret_cast<SyncLock*>(handle);
g_mutex->Init();
uint32_t *size = reinterpret_cast<uint32_t*>(g_mutex+1);
*size = 0;
char *data = reinterpret_cast<char*>(size+1);
std::string iput("input 'quit' quit while!!! ");
std::cout << iput << std::endl;
while(true){
std::getline(std::cin, iput);
g_mutex->Lock();
*size = static_cast<uint32_t>(iput.size());
if(*size > MEM_SIZE) continue;
memcpy(data, iput.data(), *size);
g_mutex->Unlock();
g_mutex->NotifyOne();
if(iput == "quit")
break;
}
munmap(handle, MEM_SIZE);
shm_unlink(key.data());
return 0;
}
消费者进程 b.cpp
#include <iostream>
#include <thread>
#include "type.h"
#include <string.h>
int main(int argc, char *argv[])
{
int fd = shm_open(key.data(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
if(fd == -1){
perror("open shm error");
return -1;
}
struct stat sb;
fstat(fd, &sb);
std::cout << sb.st_size << std::endl;
if(sb.st_size != MEM_SIZE)
ftruncate(fd, MEM_SIZE);
void *handle = mmap(NULL, MEM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(handle == MAP_FAILED){
perror("mmap error : ");
return -2;
}
close(fd);
SyncLock *g_mutex = reinterpret_cast<SyncLock*>(handle);
uint32_t *size = reinterpret_cast<uint32_t*>(g_mutex+1);
char *data = reinterpret_cast<char*>(size+1);
std::string oput;
while(true){
g_mutex->Lock();
while(*size == 0) g_mutex->Wait();
oput = std::string(data, *size);
*size = 0;
g_mutex->Unlock();
std::cout << oput << std::endl;
if(oput == std::string("quit"))
break;
}
munmap(handle, MEM_SIZE);
return 0;
}
公共头文件 type.h
#ifndef TYPE_H
#define TYPE_H
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <string>
const std::string key("POSIX_IPC_TEST_01");
const int MEM_SIZE = 4096;
struct SyncLock{
pthread_mutex_t mutex;
pthread_cond_t cond;
void Init(){
pthread_condattr_t condattr;
pthread_condattr_init(&condattr);
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init(&mutexattr);
#ifdef _POSIX_THREAD_PROCESS_SHARED
pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED);
#else
//ERROR does not support PTHREAD_PROCESS_SHARED
#endif
pthread_cond_init(&cond, &condattr);
pthread_mutex_init(&mutex, &mutexattr);
pthread_mutexattr_destroy(&mutexattr);
pthread_condattr_destroy(&condattr);
}
void Destroy(){
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
}
void Lock(){
pthread_mutex_lock(&mutex);
}
void TryLock(){
pthread_mutex_trylock(&mutex);
}
void LockTime(const struct timespec * time){
pthread_mutex_timedlock(&mutex, time);
}
void Wait(){
pthread_cond_wait(&cond, &mutex);
}
void Unlock(){
pthread_mutex_unlock(&mutex);
}
void NotifyOne(){
pthread_cond_signal(&cond);
}
void NotifyAll(){
pthread_cond_broadcast(&cond);
}
};
#endif
工程文件CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(POSIX_IPC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_executable(ch1_a ch1/a.cpp ch1/type.h)
target_link_libraries(ch1_a pthread rt)
add_executable(ch1_b ch1/b.cpp ch1/type.h)
target_link_libraries(ch1_b pthread rt)
本文围绕C++多进程同步展开,介绍了互斥量和条件变量。它们出自Posix.1线程标准,可用于线程和进程间同步。说明了其初始化分静态和动态,进程间同步用动态且需放共享内存区并设属性为共享。还提及操作步骤及生产者消费者流程,最后给出代码示例。
488

被折叠的 条评论
为什么被折叠?



