std::lock_guard使用案例及常用系统函数调用案例

1)lock_guard有两个构造函数,使用方法如下(注意:一定要声明一个局部的lock_guard对象):
std::mutex mtx;
(1)一个参数的使用方法:lock_guard lock(mtx); //直接自动上锁,相当于调用mtx.lock()函数;
(2)两个参数的使用方法:lock_guard lock1(mutex,adopt_lock); //需要手动(自己)上锁;所以在执行这条语句之前,需要手动上锁,代码如:mtx.lock();
(3) lock_guard模板类的使用,代码如下:

#include <iostream>
#include <mutex>
#include <vector>
#include <stdio.h>
#include <thread>

using namespace std;

std::string ReadMsg(void)
{
    char buf[30] = {0};
    static int i = 100;
    sprintf(buf,"%d",i--);
    return buf;
}

class CMutexTest
{
public: 
    void recv_msg();
    void read_msg();
private:
    vector<string> msgQueue;
    mutex mtx; 实例化mtx对象,不要理解为定义变量
};

void CMutexTest::recv_msg(void)
{
    while(1)
    {
        string tmpSsg = ReadMsg();
        cout<< "模拟接收数据后存入 vector数组中: " << tmpSsg <<endl;
        //使用{}限定lock_guard作用域
        {
            std::lock_guard<mutex> mylock(mtx); //用此语句替换了mtx.lock();自动锁定
            msgQueue.push_back(tmpSsg);
        }
        this_thread::sleep_for(chrono::milliseconds(5));
    }
}

void CMutexTest::read_msg(void)
{
    while(1)
    {
    	//std::lock_gurad也可以传入两个参数,第一个参数为adopt_lock标识时,表示构造函数中不再进行互斥量锁定,因此此时需要提前手动锁定。
        mtx.lock(); //提前手动锁定
        std::lock_guard<mutex> mylock(mtx,adopt_lock); //这里必须用adopt_lock这个参数
        if(!msgQueue.empty())
        {
            //处理消息并移除
            string msg = msgQueue.front();
            cout<<"从动态数组中读取数据: "<<msg<<endl;
            msgQueue.erase(msgQueue.begin());
        }
        this_thread::sleep_for(chrono::milliseconds(10));
    }
}

int main(void)
{
    CMutexTest message;
    thread th1(&CMutexTest::recv_msg,&message);
    thread th2(&CMutexTest::read_msg,&message);

    th1.join();
    th2.join();
    return 0;
}

运行结果如下:

模拟接收数据后存入 vector数组中: 100
从动态数组中读取数据: 100
模拟接收数据后存入 vector数组中: 99
从动态数组中读取数据: 99
模拟接收数据后存入 vector数组中: 98
从动态数组中读取数据: 98
模拟接收数据后存入 vector数组中: 97
从动态数组中读取数据: 97
模拟接收数据后存入 vector数组中: 96
从动态数组中读取数据: 96
模拟接收数据后存入 vector数组中: 95
从动态数组中读取数据: 95
模拟接收数据后存入 vector数组中: 94

对上面lock_guard的总结:
定义两个线程,一个是模拟从设备上(设备为自定义int型数据)读取数据后,存储到vector动态数组中;
一个线程从动态数组中读取数据后,并清除vector数组内容;
lock_guard具有两种构造方法:
lock_guard(mutex& m)
lock_guard(mutex& m, adopt_lock)
其中mutex& m是互斥量,参数adopt_lock表示假定调用线程已经获得互斥体所有权并对其进行管理了。
从lock_guard<>可以看出它是一个模板类,它在自身作用域(生命周期)中具有构造时加锁,析构时解锁的功能。

2)fread和fwrite函数应用案例(读、写二进制文件),代码如下:

#include<stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>

struct pirate
{
    char name[100];
    unsigned long booty;
    u_int16_t beard_len;
};

/*
size_t   fread(   void   *buffer,   size_t   size,   size_t   count,   FILE   *stream   ) 
  buffer   是读取的数据存放的内存的指针(可以是数组,也可以是新开辟的空间,buffer就是一个索引)   
  size     是每次读取的字节数  
  count    是读取次数  
  strean   是要读取的文件的指针  
  例如: 从文件fp里读取100个字节   可用以下语句  
   
  fread(buffer,100,1,fp)  
  fread(buffer,50,2,fp)  
  fread(buffer,1,100,fp)   
*/

//二进制文件读、写的案例 用fread 和 fwrite 库函数
//fwrite和fread用 fopen 文件指针进行数据读写;
//write和read用 open 文件描述符进行数据读写;
//文件指针和文件描述符是完全不同的两个概念;
int main(void)
{
    FILE *in, *out;
    struct pirate blackbeard = {"jiang",950,48};
    struct pirate readMsg;

    out = fopen("data","w");
    if(out == NULL)
    {
        perror("fopen");    
        return 1;
    }

    if(!fwrite(&blackbeard,sizeof(struct pirate),1,out))
    {
        perror("fwrite");    
        return 1;
    }

    if(fclose(out))
    {
        perror("fclose");    
        return 1;        
    }

    in = fopen("data","r");
    if(in == NULL)
    {
        perror("fopen");    
        return 1;
    }

    if(!fread(&readMsg,sizeof(struct pirate),1,in))
    {
        perror("fread");    
        return 1;
    }

    if(fclose(in))
    {
        perror("fclose");    
        return 1;        
    }

    printf("name: %s booty: %lu beard_len %u\r\n",  \
    readMsg.name,readMsg.booty,readMsg.beard_len);
}

输出结果如下:

name: jiang booty: 950 beard_len: 48

3)进程间通信中的信号量案例(防止死锁发生),哲学家吃饭问题的代码案例如下:

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/wait.h>
//不可能出现两个相邻的两个哲学家出现同时吃的状态!

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
 
union semun
{
    int val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO (Linux-specific) */
};
 
int semid;
 
#define DELAY (rand() % 5 + 1)
 
int wait_1fork(int no)//
{
    struct sembuf sb = {(unsigned short)no, -1, 0};//对信号量集中第no个信号进行操作,对信号量的计数值减1,
    int ret = semop(semid, &sb, 1);//用来进行P操作(信号量集标识,数组,数组中包含元素个数)
    if (ret == -1)
        ERR_EXIT("semop");
 
    return ret;
}
 
void wait_for_2fork(int no)
{
    unsigned short left = no;//哲学家左边刀叉号码
    unsigned short right = (no + 1) % 5;//哲学家右边刀叉号码
 
    struct sembuf buf[2] =
    {
        {left, -1, 0},//信号量序号、信号量的计数值减1
        {right, -1, 0}
    };
 
    semop(semid, buf, 2);
}
 
void free_2fork(int no)
{
    unsigned short left = no;
    unsigned short right = (no + 1) % 5;
 
    struct sembuf buf[2] =
    {
        {left, 1, 0},
        {right, 1, 0}
    };
 
    semop(semid, buf, 2);
}
 
void philosopere(int no)//哲学家行为
{
    srand(getpid());
    for (; ;)
    {
 
        printf("%d is thinking\n", no);//思考
        sleep(DELAY);
        printf("%d is hungry\n", no);//饿
        wait_for_2fork(no);//获取刀叉
        printf("%d is eating\n", no);//进食
        sleep(DELAY);
        free_2fork(no);//释放刀叉
/* 死锁--
		int left = no;//哲学家左边刀叉号码
		int right = (no + 1) % 5;//哲学家右边刀叉号码
        printf("%d is thinking\n", no);//思考
        sleep(DELAY);
        printf("%d is hungry\n", no);//饿
        wait_1fork(left);//看到空余的刀叉立刻拿起来
		sleep(DELAY);
		wait_1fork(right);
        printf("%d is eating\n", no);//进食
        sleep(DELAY);
        free_2fork(no);//释放刀叉
*/
    }
}
int main(void)
{
    semid = semget(IPC_PRIVATE, 5, IPC_CREAT | 0666);//创建5把刀叉资源信号集
    if (semid == -1)
        ERR_EXIT("semget");
    union semun su;
    su.val = 1;
    int i;
    for (i = 0; i < 5; i++)//将5把刀叉都置为可用状态
    {
        semctl(semid, i, SETVAL, su);//将信号集中每个信号量初始值都置为1,表示可用
    }
 
    int no = 0;//开始5个哲学家就坐(5个进程)
    pid_t pid;
    for (i = 1; i < 5; i++)//创建4个子进程
    {
        pid = fork();
        if (pid == -1)
            ERR_EXIT("fork");
 
        if (pid == 0)//说明是子进程
        {
            no = i;
            break;
        }
    }
    philosopere(no);//每个(进程)哲学家的行为
    return 0;
}

数据结果如下:

1 is thinking
2 is thinking
0 is thinking
4 is thinking
3 is thinking
3 is hungry
3 is eating
0 is hungry
0 is eating
1 is hungry
4 is hungry
2 is hungry
0 is thinking
1 is eating
3 is thinking
4 is eating
1 is thinking
2 is eating

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值