- 实现两个程序,write,read
- 在两个终端中分别运⾏write和read
- write将循环读终端输⼊,可输⼊空格,输⼊回车确定
- read进程将持续运⾏,感知到write输⼊的数据,就将该数据输出到屏幕上
代码
- read部分
#include#include #include #include #include #include #include #include #include #include void myperror(char* s) { perror(s); exit(1); } typedef struct ipcnode { pthread_mutex_t mutex; pthread_mutexattr_t mutex_attr; pthread_cond_t read, write; pthread_condattr_t cond_attr; char buf[64]; int buflen; int stat;//状态:0表示等待write,1表示write开始工作,-1表示read/write结束工作。 }ipcnode; int main() { int retlen; char buf[64]; key_t fk = ftok("./test.txt", 9); int shid = shmget(fk, 512, IPC_CREAT | 0666); ipcnode *node = shmat(shid, NULL, 0); //初始化互斥锁、条件变量、状态变量 if(pthread_mutexattr_init(&node -> mutex_attr) < 0) myperror("mutexattr_init"); if(pthread_mutexattr_setpshared(&node -> mutex_attr, PTHREAD_PROCESS_SHARED) < 0) myperror("mutexattr_setshared"); if(pthread_condattr_init(&node -> cond_attr) < 0) myperror("mutexattr_init"); if(pthread_condattr_setpshared(&node -> cond_attr, PTHREAD_PROCESS_SHARED) < 0) myperror("mutexattr_setshared"); if(pthread_mutex_init(&node -> mutex, &node -> mutex_attr) < 0) myperror("mutex_init"); if(pthread_cond_init(&node -> read, &node -> cond_attr) < 0) myperror("read_init"); if(pthread_cond_init(&node -> write, &node -> cond_attr) < 0) myperror("write_init"); pthread_condattr_destroy(&node -> cond_attr); node -> buflen = 0; node -> stat = 0; //等待write进程启动 while(node -> stat == 0) { printf("waiting for write process.n"); sleep(3); } printf("start working.n"); //开始循环写入 while((retlen = read(0, buf, 64)) > 0) { //锁逻辑:读写只能同时拥有一个mutex锁 //若共享内存中buf有数据则等待write端传递read的信号 //一次写工作完成后传递read信号并归还mutex锁 if(!strncmp(buf, "-1", 2) || node -> stat == -1) break; pthread_mutex_lock(&node -> mutex); if(node -> buflen > 0) pthread_cond_wait(&node -> read, &node -> mutex); strncpy(node -> buf, buf, retlen); node -> buflen = retlen; pthread_cond_signal(&node -> write); pthread_mutex_unlock(&node -> mutex); } //结束工作,通知write处理后续工作 printf("exiting.n"); node -> stat = -1; pthread_mutex_unlock(&node -> mutex); pthread_cond_signal(&node -> write); return 0; }
- write部分
#include#include #include #include #include #include #include #include #include #include typedef struct ipcnode { pthread_mutex_t mutex; pthread_mutexattr_t mutex_attr; pthread_cond_t read, write; pthread_condattr_t cond_attr; char buf[64]; int buflen; int stat;//状态:1表示read工作,-1表示read结束工作。 }ipcnode; int main() { //挂载共享内存 key_t fk = ftok("./test.txt", 9); int shid = shmget(fk, 512, IPC_EXCL | 0666); if(shid < 0) { perror("shmget"); exit(1); } ipcnode *node = shmat(shid, NULL, 0); node -> stat = 1;//通知read端开始工作 while(1) { //锁逻辑:读写只能同时拥有一个mutex锁 //若共享内存中buf没有数据则等待read端传递write的信号 //一次写工作完成后传递read信号并归还mutex锁 pthread_mutex_lock(&node -> mutex); if(node -> buflen == 0) pthread_cond_wait(&node -> write, &node -> mutex); //如果读端主动关闭程序,跳出循环,进行善后工作 if(node -> stat == -1) break; write(1, node -> buf, node -> buflen); node -> buflen = 0; pthread_cond_signal(&node -> read); pthread_mutex_unlock(&node -> mutex); } //结束善后工作 //销毁锁和删除共享内存 pthread_mutex_destroy(&node -> mutex); pthread_cond_destroy(&node -> read); pthread_cond_destroy(&node -> write); pthread_condattr_destroy(&node -> cond_attr); shmctl(shid, IPC_RMID, 0); return 0; }
重要结构说明
typedef struct ipcnode
{
pthread_mutex_t mutex;//互斥锁、进程间共享
pthread_mutexattr_t mutex_attr;//互斥锁属性、设置互斥锁为进程间共享
pthread_cond_t read, write;//条件锁、进程间共享
pthread_condattr_t cond_attr;//条件锁属性、设置条件锁为进程间共享
char buf[64];//读写缓冲区
int buflen;//缓冲区已有数据长度
int stat;//状态:1表示read工作,-1表示read结束工作。
}ipcnode;
pthread_mutexattr_t mutex_attr 和 pthread_condattr_t cond_attr 的作用是设置锁的属性,只在初始化的时刻起作用,初始化时永久设置锁的属性。这里一开始不知道这个东西放了什么怕是一直起作用就把他放入共享内存了- -,实践可以不放入共享内存中,甚至初始化锁完后销毁 attr 也没问题。
运行截图
笔记
-
共享内存相关
-
生成fk值:key_t ftok(const char *pathname, int proj_id);
根据path那么和id综合参数哈希出一个结果保存到key_t变量中,便于后面进程通信操作。
-
创建共享内存:int shmget(key_t key, size_t size, int shmflg);
根据上面得到的key创建一个size大小的共享内存区,shmflg设置用户权限和相关属性,跟open类似,返回shmid。
-
挂载共享内存:void *shmat(int shmid, const void *shmaddr, int shmflg);
根据上面得到的shmid就可以挂载共享内存了,第二个参数是建议在哪个地址开始申请空间,shmflg一般设置为0即可,返回挂载共享内存的首地址。
-
解挂共享内存:int shmdt(const void *shmaddr);
传入一个挂载的共享内存首地址即可解挂。
-
删除共享内存:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
传入shmid、cmd设置为 IPC_RMID 宏、buf中储存有关于共享内存的一些数据,这里设置为0即可。
-
-
互斥锁/条件变量如何在进程中共享
-
以互斥锁为例,有init函数int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); 其中第二个参数用来设置锁的属性。
我们可以通过创建一个 pthread_condattr_t attr 变量,执行int pthread_condattr_init(pthread_condattr_t *attr);初始化后在对变量执行pthread_condattr_setpshared(&node -> cond_attr, PTHREAD_PROCESS_SHARED)设置属性,其中第二个参数传入的宏PTHREAD_PROCESS_SHARED是设置锁在进程间共享。
-
-
条件变量
-
当我们需要争夺两个资源时,可以使用条件变量。
例如本作业中读端除了要获取互斥锁进行读操作之外、缓冲区是否有数据也是是否能进行读操作的条件。因此我们需要使用条件变量:当缓冲区有数据时,归还互斥锁并阻塞等待写端写完数据发出read信号,只有在收到read信号后读端才能进行读操作。写端同理。
-



