Linux互斥与同步应用(四):posix信号量的互斥与同步
#include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <semaphore.h> sem_t *sem_open(const char *name, int oflag); sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); Link with -pthread
#include <semaphore.h> int sem_close(sem_t *sem); Link with -pthread.
#include <semaphore.h> int sem_unlink(const char *name); Link with -pthread.
#include <semaphore.h> int sem_wait(sem_t *sem); int sem_trywait(sem_t *sem); int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); Link with -pthread.
#include <semaphore.h> int sem_post(sem_t *sem); Link with -pthread.
#include <semaphore.h> int sem_getvalue(sem_t *sem, int *sval); Link with -pthread.
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); Link with -pthread.
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; ...... pthread_mutex_lock(&mutex);//加锁 ...... /*share memory handle*/ ...... pthread_mutex_unlock(&mutex);//解锁 ......现在我们也使用类似方式来实现:sem_t *sem_mutex = NULL; ...... SLN_MUTEX_SHM_LOCK(SEM_MUTEX_FILE, sem_mutex);//加锁 ...... /*share memory handle*/ ...... SLN_MUTEX_SHM_UNLOCK(sem_mutex);//解锁 ......其中SEM_MUTEX_FILE为sem_open函数需要的有名信号量名称。
其中两个加锁解锁的实现为:#define SLN_MUTEX_SHM_LOCK(shmfile, sem_mutex) do { sem_mutex = sem_open(shmfile, O_RDWR | O_CREAT, 0666, 1); if (SEM_FAILED == sem_mutex) { printf("sem_open(%d): %s\n", __LINE__, strerror(errno)); } sem_wait(sem_mutex);}while(0) #define SLN_MUTEX_SHM_UNLOCK(sem_mutex) do {sem_post(sem_mutex);} while(0)其实就是初始化一个二值信号量,其初始值为1,并执行wait操作,使信号量的值变为0,此时其它进程想要操作共享内存时也需要执行wait操作,但此时信号量的值为0,所以开始等待信号量的值变为1。当当前进程操作完共享内存后,开始解锁,执行post操作将信号量的值加一,此时其它进程的wait可以返回了。下面为一个互斥访问共享内存的示例,posix共享内存实现请查看前面IPC的系列文章。ser process:int nms_shm_get(char *shm_file, void **shm, int mem_len) { int fd; fd = shm_open(shm_file, O_RDWR | O_CREAT, 0666); if (fd < 0) { printf("shm_pen <%s> failed: %s\n", shm_file, strerror(errno)); return -1; } ftruncate(fd, mem_len); *shm = mmap(NULL, mem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (MAP_FAILED == *shm) { printf("mmap: %s\n", strerror(errno)); return -1; } return 0; } int main(int argc, const char *argv[]) { sem_t *sem_mutex = NULL; char *str = NULL; SLN_MUTEX_SHM_LOCK(SEM_MUTEX_FILE, sem_mutex); //加锁 nms_shm_get(SHM_FILE, (void **)&str, SHM_MAX_LEN); //下面三行互斥访问共享内存 sleep(6); snprintf(str, SHM_MAX_LEN, "posix semphore server!"); SLN_MUTEX_SHM_UNLOCK(sem_mutex); //解锁 sleep(6); shm_unlink(SHM_FILE); return 0; }client process:int main(int argc, const char *argv[]) { sem_t *sem_mutex; char *str = NULL; SLN_MUTEX_SHM_LOCK(SEM_MUTEX_FILE, sem_mutex); nms_shm_get(SHM_FILE, (void **)&str, SHM_MAX_LEN); printf("client get: %s\n", str); SLN_MUTEX_SHM_UNLOCK(sem_mutex); return 0; }先启动服务进程首先加锁,创建共享内存并操作它,加锁中sleep 6秒,以便测试客户进程是否在服务进程未释放锁时处于等待状态。客户进程在服务进程启动之后马上启动,此时处于等待状态,当服务进程6秒之后解锁,客户进程获得共享内存信息。再过6秒之后,服务进程删除共享内存,客户进程再此获取共享内存失败。# ./server & [1] 21690 # ./client client get: posix semphore server! # ./client shm_open <share_memory_file> failed: No such file or directory client get: (null) [1]+ Done ./serverposix有名信号量创建的信号量文件和共享内存文件在/dev/shm/目录下:# ls /dev/shm/ sem.sem_mutex share_memory_file #在两个进程共享数据时,当一个进程向共享内存写入了数据后需要通知另外的进程,这就需要两个进程之间实现同步,这里我们给上面的程序在互斥的基础上加上同步操作。同步也是使用posix信号量来实现。server process:int main(int argc, const char *argv[]) { sem_t *sem_mutex = NULL; sem_t *sem_consumer = NULL, *sem_productor = NULL; int semval; char *sharememory = NULL; sem_consumer = sem_open(SEM_CONSUMER_FILE, O_CREAT, 0666, 0); //初始化信号量sem_consumer ,并设置初始值为0 if (SEM_FAILED == sem_consumer) { printf("sem_open <%s>: %s\n", SEM_CONSUMER_FILE, strerror(errno)); return -1; } sem_productor = sem_open(SEM_PRODUCTOR_FILE, O_CREAT, 0666, 0);//初始化信号量sem_productor ,并设置初始值为0 if (SEM_FAILED == sem_productor) { printf("sem_open <%s>: %s\n", SEM_PRODUCTOR_FILE, strerror(errno)); return -1; } for (;;) {//服务进程一直循环处理客户进程请求 sem_getvalue(sem_consumer, &semval); printf("%d waiting...\n", semval); if (sem_wait(sem_consumer) < 0) {//如果sem_consumer为0,则阻塞在此,等待客户进程post操作使sem_consumer大于0,此处和客户进程同步 printf("sem_wait: %s\n", strerror(errno)); return -1; } printf("Get request...\n"); SLN_MUTEX_SHM_LOCK(SEM_MUTEX, sem_mutex);//此处开始互斥访问共享内存 nms_shm_get(SHM_FILE, (void **)&sharememory, SHM_MAX_LEN); sleep(6); snprintf(sharememory, SHM_MAX_LEN, "Hello, this is server's message!"); SLN_MUTEX_SHM_UNLOCK(sem_mutex); sem_post(sem_productor);//使信号量sem_productor加一,使阻塞的客户进程继续执行 printf("Response request...\n"); } sem_close(sem_consumer); sem_close(sem_productor); return 0; }client process:
int main(int argc, const char *argv[]) { sem_t *sem_consumer = NULL, *sem_productor = NULL; struct timespec timeout; int ret; char *sharememory = NULL; sem_t *sem_mutex; sem_consumer = sem_open(SEM_CONSUMER_FILE, O_RDWR);//获取信号量sem_consumer的值 if (SEM_FAILED == sem_consumer) { printf("sem_open <%s>: %s\n", SEM_CONSUMER_FILE, strerror(errno)); return -1; } sem_productor = sem_open(SEM_PRODUCTOR_FILE, O_RDWR);//获取信号量sem_productor 的值 if (SEM_FAILED == sem_productor) { printf("sem_open <%s>: %s\n", SEM_PRODUCTOR_FILE, strerror(errno)); return -1; } //clear_exist_sem(sem_productor); SLN_MUTEX_SHM_LOCK(SEM_MUTEX, sem_mutex);//互斥访问共享内存 nms_shm_get(SHM_FILE, (void **)&sharememory, SHM_MAX_LEN); printf("sharememory: %s\n", sharememory); SLN_MUTEX_SHM_UNLOCK(sem_mutex); sem_post(sem_consumer);//信号量sem_consumer加一,唤醒是阻塞在该信号量上的服务进程 printf("Post...\n"); sem_wait(sem_productor);//等待服务进程回应 /* timeout.tv_sec = time(NULL) + SEM_TIMEOUT_SEC; timeout.tv_nsec = 0; ret = sem_timedwait(sem_productor, &timeout); if (ret < 0) { printf("sem_timedwait: %s\n", strerror(errno)); } */ printf("Get response...\n"); sem_close(sem_consumer); sem_close(sem_productor); return 0; }本节示例源码下载:
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。