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
#include
#include
#include
#include
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
#include
#include
#include
#include
#include
#include
#include
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
#include
#include
#include
#include
#include
#include
#include
#include
#include
//不可能出现两个相邻的两个哲学家出现同时吃的状态!
#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