linux 多进程 posix semaphore 二值,Linux互斥与同步应用(4):posix信号量的互斥与同步...

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 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 failed: No such file or directory

client get: (null)

[1]+ Done ./server

posix有名信号量创建的信号量文件和共享内存文件在/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\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\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\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\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;

}

本节示例源码下载:

点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值