互斥量 共享内存 对线程中文件操作

  1. 互斥量的概念:
    互斥量是另一种用于多线程中的同步访问方法,它允许程序锁住某个对象,使得每次只能有一个线程访问它。为了控制对关键代码的访问,必须在进入这段代码之前锁住一个互斥量,然后在完成操作之后解锁。

  2. 共享内存的概念:
    共享内存是由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);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值