基於記憶體的posix訊號量用法
阿新 • • 發佈:2019-02-06
posix訊號量的兩種形式
基於檔案系統
不打算詳細講細節,提供兩種模板,簡單的用法
#include <semaphore.h>
sem_t* sem_open(const char*name,int oflag,.../*mode_t mode,unsigned int value*/)
oflag引數我一般指定O_CREAT|O_RDWR,因為一般不儲存訊號量,畢竟總覺得這東西會一直佔系統資源,所以我建立時指定O_CREAT,意思就是如果不存在和這個訊號量,則建立並初始化它,若存在則為這個訊號量重新賦值。一般程式退出時刪除它。
mode引數可以參考man 2 open。我一般指定#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH),方便好用。
int sem_close(semt_t *sem);
注意,close一個訊號量並沒釋放它的資源,posix訊號量至少是隨核心持續的,close只是“扯斷這個訊號量和程序的聯絡”。我們要真的刪除某個訊號量時,應該用
int sem_unlink(sem_t *sem);
刪除僅當沒有任何程序還開啟這個訊號量時成功
PV操作
int sem_wait(sem_t *sem);//p opration
int sem_post(sem_t *sem);//v opration
這就是作業系統課上講的PV操作
demo
兩個程序,mmap共享一個記憶體,通過訊號量來管理這個共享記憶體。一個程序從stdin收取字串,並寫入共享記憶體,然後V訊號量
另一個程序P訊號量,拿走字串,v訊號量。輸出到stdout。
傳送程式輸入exit,可以將接收程式終止
注意 編譯時要連結 lrt或者lpthread
Send.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
char buf[1024];
int main()
{
sem_t *mutex = sem_open("wudi_sem",O_CREAT|O_RDWR,FILE_MODE,0);
int fd = open("0xabc",O_CREAT|O_RDWR,FILE_MODE);
char *sharedFile = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(!sharedFile)
{
perror("mmap:");
sem_unlink("wudi_sem");
exit(-1);
}
write(fd,buf,1024);
close(fd);
while(scanf("%s",buf)!=EOF)
{
memcpy(sharedFile,buf,128);
sem_post(mutex);
}
sem_unlink("wudi_sem");
printf("unlink mutex\n");
return 0;
}
Recv.c
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
char buf[1024];
int main()
{
sem_t *mutex = sem_open("wudi_sem",O_RDWR);
int fd = open("0xabc",O_RDWR);
if(fd<0)
{
perror("open:");
exit(-1);
}
char *sharedFile = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(!sharedFile)
{
perror("mmap:");
sem_unlink("wudi_sem");
exit(-1);
}
close(fd);
while(1)
{
sem_wait(mutex);
memcpy(buf,sharedFile,128);
if(strcmp(buf,"exit")==0)
{
printf("ready to exit\n");
break;
}
printf("get msg>> %s\n",buf);
}
sem_unlink("wudi_sem");
printf("unlink mutex\n");
return 0;
}
注意以上兩個程式並未十分安全的處理臨界區,send方對共享記憶體的寫其實並不安全,因為可能recv方正在讀取那個資料,正確的做法應該是將共享記憶體做成一個佇列,這樣寫的位置和讀的位置就能避免衝突。但此處僅作演示用,而且從stdin收東西其實很慢的。。。。。
基於共享記憶體的訊號量
int sem_init(sem_t *sem,int shared,int value);
int sem_destroy(sem_t *sem);
注意:
- sem的記憶體由呼叫者自己分配,並得確保這個記憶體一直存在
- 不要重複對一個訊號量呼叫sem_init(),其結果是未定義的
- 不要copy訊號量,使用copy後的訊號量的副本,其結果是未定義的
- sem_init失敗時返回-1,但成功時並不返回0
- 就算是在stack空間上分配的空間,也要在不使用時,呼叫sem_destroy釋放資源
其中 shared 引數 指示是否在程序間共享
demo
將上一個例子改成基於共享記憶體的訊號量
Send.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
char buf[1024];
int main()
{
sem_t *mutex; //= sem_open("wudi_sem",O_CREAT|O_RDWR,FILE_MODE,0);
char *dataStart;
int fd = open("0xabc",O_CREAT|O_RDWR,FILE_MODE);
char *sharedFile = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(!sharedFile)
{
perror("mmap:");
sem_unlink("wudi_sem");
exit(-1);
}
write(fd,buf,1024);
close(fd);
mutex = (sem_t*)sharedFile;
if(sem_init(mutex,1,0) < 0)
{
perror("mutex init");
exit(-1);
}
dataStart = (char*)sharedFile + sizeof(sem_t);
while(scanf("%s",buf)!=EOF)
{
memcpy(dataStart,buf,128);
sem_post(mutex);
}
sem_destroy(mutex);
printf("exit\n");
return 0;
}
Recv.c
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
// void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
char buf[1024];
int main()
{
sem_t *mutex; //= sem_open("wudi_sem",O_RDWR);
char *dataStart;
int fd = open("0xabc",O_RDWR);
if(fd<0)
{
perror("open:");
exit(-1);
}
char *sharedFile = mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(!sharedFile)
{
perror("mmap:");
sem_unlink("wudi_sem");
exit(-1);
}
close(fd);
mutex = (sem_t*)sharedFile;
//make sure there exist a sempahore at the start of sharedFile
dataStart = (char*)sharedFile + sizeof(sem_t);
while(1)
{
sem_wait(mutex);
memcpy(buf,dataStart,128);
if(strcmp(buf,"exit")==0)
{
printf("ready to exit\n");
break;
}
printf("get msg>> %s\n",buf);
}
sem_destroy(mutex);
printf("exit\n");
return 0;
}