您的位置:首页 > 文旅 > 旅游 > 推广普通话征文_ppt模板下载网址_长尾词挖掘免费工具_软件外包公司排名

推广普通话征文_ppt模板下载网址_长尾词挖掘免费工具_软件外包公司排名

2025/5/3 17:47:07 来源:https://blog.csdn.net/Mr_Hanc_Tiskor/article/details/147621894  浏览:    关键词:推广普通话征文_ppt模板下载网址_长尾词挖掘免费工具_软件外包公司排名
推广普通话征文_ppt模板下载网址_长尾词挖掘免费工具_软件外包公司排名

前言

对于数据库(可以看作共享内存)等高并发的服务器,需要同时应对很多请求,这些请求里有读请求也有写请求。如果每次来一个请求的时候就给数据库加一个锁,或者使用单一信号量限制单进程访问,那么系统的性能会受到极大的影响,失去多进程的优势。为了解决这个问题,可以考虑使用读写锁。

读写锁

读写锁的功能
读写锁是指,当允许多个进程同时以读的方式访问共享资源,但是只能允许一个进程向共享资源内写入数据,同时在写入数据时不能有进程在读数据。
总结一下,读写锁需要满足以下功能:
(1)可以允许多个进程读数据。
(2)只能有一个进程写数据。
(3)写数据的时候不能有进程读数据。
其实很好理解,因为读数据不会对数据本身造成影响,因此多个进程间不会出现冲突。而如果多个进程写数据可能会导致内容相互覆盖。同时写和读也可能得到混乱的数据。
读写锁的结构
读写锁内部由两个子锁构成,分别为共享锁和独占锁。
在独占锁存在的前提下,读进程会获取共享锁并访问共享内存。与之不同的是,写进程在执行写动作时,会检查独占锁是否存在。若存在,他会获取独占锁,之后所有的读进程和写进程都无法访问共享内存。此时读进程可能还没完成读操作,因此写进程需要等待所有读进程离开后才开始写入。
请看下面的组图:
在这里插入图片描述
这里有一个歧义之处:读进程获取共享锁是指对共享锁记录的值加一,而写进程获取独占锁是将独占锁由1变为0。因此实际上共享锁就是一个计数器,表示目前访问共享内存的读进程的个数。而独占锁相当于一个状态位,表示现在共享内存内是否有写进程。之前讲过使用普通的变量在多进程的情况下会有冲突的情况,因此为了保证安全,这里需要使用信号量,而且需要使用两个信号量。

代码解析与实现:

接下来结合代码讲解:

1、关键结构声明与初始化:


typedef struct rwlock {int unique;int shared;
} rwlock;union semun {int val;                // SETVAL用的值struct semid_ds *buf;   // IPC_STAT, IPC_SET用的缓冲区unsigned short *array;  // GETALL, SETALL用的数组
};	// 用于追加参数的一个结构体,必须由用户定义int rwlock_init(rwlock* rw) {rw->unique = semget(1, 1, 0666 | IPC_CREAT | IPC_EXCL);rw->shared = semget(2, 1, 0666 | IPC_CREAT | IPC_EXCL);if(rw->unique == -1 && rw->shared == -1) {if(errno == EEXIST) {	// 信号量已经存在printf("rwlock has exist\n");rw->unique = semget(1, 1, 0666);rw->shared = semget(2, 1, 0666);}else { exit(0); }}else if(rw->unique > -1 && rw->shared > -1) {	// 信号量不存在,新创建printf("rwlock is created\n");union semun arg;arg.val = 1;semctl(rw->unique, 0, SETVAL, arg);arg.val = 0;semctl(rw->shared, 0, SETVAL, arg);}else { // another errorexit(0);}return 0;
}void* shm_init() {int id = shmget(1, 128, 0666|IPC_CREAT);return shmat(id, NULL, 0);
}

这里其实很简单,rwlock结构里里面是两个整形,用于表示两个信号量的id,在rwlock_init中对信号量进行了初始化和赋值。为了防止重读赋值导致rwlock_init的逻辑较为复杂,但是结合注释仔细阅读也没有什么特别难以理解的。shm_init用来初始化共享内存。

2、写操作的实现

// buf: 指向共享内存
// data: 写入的数据
void myWrite(rwlock* rw, char* buf, const char* data) {struct sembuf sbf;sbf.sem_flg = 0;sbf.sem_num = 0;// 独占锁被获取,进入临界区sbf.sem_op = -1;semop(rw->unique, &sbf, 1);// 等待共享锁的信号量值为0sbf.sem_op = 0;semop(rw->shared, &sbf, 1);/*writing      your code */// 独占锁被释放,离开临界区sbf.sem_op = 1;semop(rw->unique, &sbf, 1);
}

读操作没什么好说的,比较关键的是,这里涉及到一个semop操作,当sbf.sem_op<0时信号量减,sbf.sem_op>0时信号量加,sbf.sem_op=0的时候则进程会被阻塞直到信号量的值变为0。(关于信号量:linux多线(进)程编程——(9)信号量(一))

3、读操作的实现

// buf: 指向共享内存
// data: 接收数据的缓存
void myRead(rwlock* rw, char* buf, chat* data) {struct sembuf sbf;sbf.sem_flg = 0;sbf.sem_num = 0;// 获取独占锁,之后会马上释放,主要为了检查读占锁是否被写进程获取sbf.sem_op = -1;semop(rw->unique, &sbf, 1);// 共享计数加一sbf.sem_op = 1;semop(rw->shared, &sbf, 1);// 释放独占锁sbf.sem_op = 1;semop(rw->unique, &sbf, 1);/*reading    your code */// 读完成,共享计数减一,表示读进程离开共享内存sbf.sem_op = -1;semop(rw->shared, &sbf, 1);
}

这里要注意的是,当读进程访问内存前,需要判断独占锁是否存在,当独占锁存在时,才可以进入。因此这里需要先获取独占锁。当独占锁为0时,证明共享内存中有写进程,需要阻塞当前读进程。
这里只提供了代码框架,具体的写入操作需要大家在我代码块留下的注释那里加入。

code sample

代码存储在我的github仓库下,LinuxMultiProcessProj
这里是一个使用案例。

1:rw.c

#ifndef __RW_H__
#define __RW_H__#include <stdio.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>int initState = 0;typedef struct rwlock {int unique;int shared;
} rwlock;union semun {int val;                // SETVAL用的值struct semid_ds *buf;   // IPC_STAT, IPC_SET用的缓冲区unsigned short *array;  // GETALL, SETALL用的数组
};	// 用于追加参数的一个结构体,必须由用户定义int rwlock_init(rwlock* rw) {rw->unique = semget(1, 1, 0666 | IPC_CREAT | IPC_EXCL);rw->shared = semget(2, 1, 0666 | IPC_CREAT | IPC_EXCL);if(rw->unique == -1 && rw->shared == -1) {if(errno == EEXIST) {printf("rwlock has exist\n");rw->unique = semget(1, 1, 0666);rw->shared = semget(2, 1, 0666);}else {printf("fatal error in %s, %s, %d, rwlock init fail\n" \, __FILE__ , __func__, __LINE__);exit(0);}}else if(rw->unique > -1 && rw->shared > -1) {printf("rwlock is created\n");union semun arg;arg.val = 1;semctl(rw->unique, 0, SETVAL, arg);arg.val = 0;semctl(rw->shared, 0, SETVAL, arg);}else {printf("fatal error in %s, %s, %d, rwlock init fail\n" \, __FILE__ , __func__, __LINE__);exit(0);}return 0;
}void* shm_init() {int id = shmget(1, 128, 0666|IPC_CREAT);return shmat(id, NULL, 0);
}void myWrite(rwlock* rw, char* buf, const char* data) {struct sembuf sbf;sbf.sem_flg = 0;sbf.sem_num = 0;sbf.sem_op = -1;semop(rw->unique, &sbf, 1);int readerNum = semctl(rw->shared, 0, GETVAL);printf("Writer : there are %d readers now\n", readerNum);sbf.sem_op = 0;semop(rw->shared, &sbf, 1);printf("Writer : all readers have left, begin writing\n");strcpy(buf, data);sleep(3);printf("Writer : write over\n");sbf.sem_op = 1;semop(rw->unique, &sbf, 1);
}void myRead(rwlock* rw, char* buf, char* data) {struct sembuf sbf;sbf.sem_flg = 0;sbf.sem_num = 0;sbf.sem_op = -1;semop(rw->unique, &sbf, 1);sbf.sem_op = 1;semop(rw->shared, &sbf, 1);sbf.sem_op = 1;semop(rw->unique, &sbf, 1);printf("Reader : I am reading\n");strcpy(data, buf);sleep(2);printf("Reader : read over\n");sbf.sem_op = -1;semop(rw->shared, &sbf, 1);
}#endif

2:writer.c

#include "rw.h"int main() {printf("Writer : Writer is begin\n");rwlock rw;if(0 > rwlock_init(&rw) ) {printf("Writer : rwlock init fail\n");return 0;}else printf("Writer : rwlock init success\n");char* buf = shm_init();if(!buf) {printf("Writer : shared memory init fail\n");return 0;}else printf("Writer : shared memory init success\n");while(1) {myWrite(&rw, buf, "hello world!\n");sleep(3);}return 0;
}

3:reader.c

#include "rw.h"int main() {printf("Reader : Writer is begin\n");rwlock rw;if( 0 > rwlock_init(&rw) ) {printf("Reader : rwlock init fail\n");return 0;}else printf("Reader : rwlock init success\n");char* shmbuf = shm_init();if(!shmbuf) {printf("Reader : shared memory init fail\n");return 0;}else printf("Reader : shared memory init success\n");char data[100];while(1) {myRead(&rw, shmbuf, data);printf("%s", data);usleep(200*1000);}return 0;
}

小结

这里的读写锁还不完善,但是基本的功能以及思想才是这篇文章想要传达的,希望大家看完有所收获。

传送阵:
上一篇:linux多线(进)程编程——(9)信号量(二)
下一篇:Linux多线(进)程编程——(10)信号

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com