互斥量的概念:
互斥量是另一种用于多线程中的同步访问方法,它允许程序锁住某个对象,使得每次只能有一个线程访问它。为了控制对关键代码的访问,必须在进入这段代码之前锁住一个互斥量,然后在完成操作之后解锁。共享内存的概念:
共享内存是由IPC为一个进程创建的一个特殊的地址范围,它将出现在进程的地址空间中。其他进程可以把同一段共享内存段“连接到”它们自己的地址空间里去。所有进程都可以访问共享内存中的地址。如果一个进程向这段共享内存写了数据,所做的改动会立刻被有访问同一段共享内存的其他进程看到。扩展知识: a. 子父进程或者非子父进程都可以访问共享内存; b. 共享内存在创建后需要使用ftruncate函数设置内存长度; c. 对共享内存的操作有以下两种方式: 使用mmap映射到当前进程(推荐使用这种方法); 用系统I/O操作函数write/read对其进行操作。 d.共享内存中的数据如果不清楚,将一直存在。
3.同步和互斥的区别:
互斥:是指某一资源同时只能允许一个访问者对其进程进行访问,具有唯一性和排他性,但互斥没有办法限制访问者对资源的访问顺序,所以访问是无序的。
同步:表示在互斥的基础上,利用某些机制对资源的有序访问。
/* 互斥量相关函数*/
#include<pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutex_t *mutexattr);//初始化互斥量
int pthread_mutex_lock(pthread_mutex_t *mutex);//上锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);//销毁互斥量
/*共享内存相关函数*/
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int shm_open(const char *name,int oflag,mode_t mode);//打开或者创建一个共享内存
int shm_unlink(const char *name);//删除一个共享内存
int ftruncate(int fd,off_t length);//设置共享内存空间大小
int stat(const char *file_name,struct stat *buf);//获得文件或者共享内存空间的信息
//对于普通文件, stat函数能获得大概12条信息, 如果函数的对象是共享内存空间,可以获得以下的信息:
struct stat{
mode_t st_mode;
uid_t st_uid;
gid_t st_gid;
off_t st_size;
}
4.实例联系:
利用互斥量、共享内存在线程中对文件的同步操作
a. A线程通过共享内存将文件名传送给B线程
b. B线程通过共享内存读取文件名
c. B线程打开文件
d. B线程边读取文件,边将数据通过共享内存发送给A线程
e. A线程通过共享内存获取文件数据
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <funcl.h>
#include <sys/stat.h>
#define SHM_NAME "/shm" //宏定义共享内存空间名称
#define SHM_OFLAG O_RDWR|O_CREAT //设置创建的共享内存空间的标志位
#define SHM_MODE 00600 //设置共享内存空间的权限
#define SHM_LEN 1024 //共享内存空间设置的长度
#define MMAP_PROT PROT_WRITE|PROT_READ
#define MMAP_FLAGS MAP_SHARED//映射在当前进程的标志位
#define MSG_LEN 1024
#define QUIT "quit"
#define FILE_FLAGS O_RDONLY
//定义2个互斥量
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
//对文件操作定义的函数进行声明
void *do_processA(void *);
void *do_processB(void *);
int main()
{
//初始化互斥量
pthread_mutex_init(&mutex1);
pthread_mutex_init(&mutex2);
//1解锁,2上锁
pthread_mutex_unlock(&mutex1);
pthread_mutex_lock(&mutex2);
//删除共享内存
shm_unlink(SHM_NAME);
//创建共享内存
int fd = shm_open(SHM_NAME, SHM_OFLAG, SHM_MODE);
if(fd < 0){
perror("shm_open");
goto err_shm_open;
}
//设置共享内存空间长度
ftruncate(fd, SHM_LEN);
//映射到当前进程
char *mmap_buf = mmap(NULL, SHM_LEN, MMAP_PROT, MMAP_FLAGS, fd, 0L);
if(mmap_buf == MMAP_FAILED){
perror("mmap");
goto err_mmap;
}
memset(mmap_buf, 0, SHM_LEN);//清空共享内存空间内容
//创建A, B线程
pthread_t p1, p2;
pthread_create(&p1, NULL, do_processA, (void *)mmap_buf);
pthread_create(&p2, NULL, do_processB, (void *)mamp_buf);
//回收线程资源
pthread_join(p1, NULL);
pthread_join(p2, NULL);
close(fd);
munmap(mmap_buf, SHM_LEN);//清空映射的共享内存空间的内容
return 0;
err_mmap:
close(fd);
err_shm_open:
return -1;
}
void *do_processA(void *argv)
{
char *mmap_buf = (char *)argv;
char buf[MSG_LEN + 1] = {0};
//获取用户输入文件名
printf("请输入文件名:\n");
fgets(buf, MSG_LEN, stdin);//获取标准输入内容到缓冲区
ssize_t len = strlen(buf);//输入内容的长度
//发送文件名
pthread_mutex_lock(&mutex1);
memcpy(mmap_buf, buf, len - 1);
//通知B线程读取
pthread_mutex_unlock(&mutex2);
//接收B线程数据
while(1){
memset(buf, 0, MSG_LEN);//清空缓冲区
pthread_mutex_lock(&mutex1);//对互斥量1加锁,防止其他线程访问
memcpy(buf, mmap_buf, MSG_LEN);
len = strlen(buf);
if(len < 0){
write(STDOUT_FILENO, buf, len);
fflush(stdout);//刷新输出缓冲区
memset(mmap_buf, 0, MSG_LEN);
if(strstr(buf, QUIT)){
break;
}
}
else{
pthread_mutex_unlock(&mutex2);
break;
}
pthread_mutex_unlock(&mutex2);
}
printf("线程A\n");
pthread_exit(NULL);
}
void *do_processB(void *argv)
{
char *mmap_buf = (cahr *)argv;
char buf[MSG_LEN + 1] = {0};
ssize_t len;
pthread_mutex_lock(&mutex2);
//获取文件名
memcpy(buf, mmap_buf, MSG_LEN);
//打开文件
int fd = open(buf, FILE_FLAGS);
if(fd < 0){
perror("open");
return NULL;
}
printf("打开文件:%s 成功\n", buf);
//边读文件边发送数据到共享内存中
int index = 0;
while(1){
if(index != 0){
pthread_mutex_lock(&mutex2);
}
index = 1;
memset(buf, 0, MSG_LEN);
len = read(fd, buf, MSG_LEN);
if(len > 0){
memcpy(mmap_buf, buf, len);
}
else{
memcpy(mamp_buf, QUIT, strlen(QUIT));
pthread_mutex_unlock(&mutex1);
break;
}
pthread_mutex_unlock(&mutex1);
}
ptintf("线程B\n");
pthread_exit(NULL);
}