制作网站的分类,工业设计公司深圳本也设计,wordpress主题识别,粤健康app下载一、接入阿里云 二、C语言调用阿里云人脸识别接口 三、System V消息队列和POSIX 消息队列
一、接入阿里云
在之前树莓派的人脸识别方案采用了翔云平台的方案去1V1上传比对两张人脸比对#xff0c;这种方案是可行#xff0c;可 以继续采用。但为了接触更多了云平台方案…一、接入阿里云 二、C语言调用阿里云人脸识别接口 三、System V消息队列和POSIX 消息队列
一、接入阿里云
在之前树莓派的人脸识别方案采用了翔云平台的方案去1V1上传比对两张人脸比对这种方案是可行可 以继续采用。但为了接触更多了云平台方案在Orange Pi Zero2里 讲采用人脸搜索1:N方案通过提 前在阿里云人脸数据库里存储人脸照片后输入单张已授权人脸图像与人脸库中人脸图片进行对比 最终获取比对结果。
官网地址如下https://vision.aliyun.com/
点击“人脸搜索1:N” 点击立即开通 使用阿里云APP/支付宝/钉钉扫码登录 购买“人脸搜索1:N”能力第一次购买可以有5000次的免费使用 开通完后 在”工作台-开发能力-人脸人体-人脸数据库管理 添加人脸照片样本 上传数据库后安装阿里云人脸识别SDK:
pip install alibabacloud_facebody20191230导入ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET环境变量
vi ~/.bashrc #最后的结尾添加 在垃圾分类的项目里如果已经添加过就不需要添加了
export ALIBABA_CLOUD_ACCESS_KEY_ID你的KEY_ID
export ALIBABA_CLOUD_ACCESS_KEY_SECRET你的KEY_SECRECT可以拿同一人的照片和不同人的照片用官方python代码进行对比
# -*- coding: utf-8 -*-
# 引入依赖包
# pip install alibabacloud_facebody20191230
# face.pyimport os
import io
from urllib.request import urlopen
from alibabacloud_facebody20191230.client import Client
from alibabacloud_facebody20191230.models import SearchFaceAdvanceRequest
from alibabacloud_tea_openapi.models import Config
from alibabacloud_tea_util.models import RuntimeOptionsconfig Config(# 创建AccessKey ID和AccessKey Secret请参考https://help.aliyun.com/document_detail/175144.html。# 如果您用的是RAM用户的AccessKey还需要为RAM用户授予权限AliyunVIAPIFullAccess请参考https://help.aliyun.com/document_detail/145025.html。# 从环境变量读取配置的AccessKey ID和AccessKey Secret。运行代码示例前必须先配置环境变量。access_key_idos.environ.get(ALIBABA_CLOUD_ACCESS_KEY_ID),access_key_secretos.environ.get(ALIBABA_CLOUD_ACCESS_KEY_SECRET),# 访问的域名endpointfacebody.cn-shanghai.aliyuncs.com,# 访问的域名对应的regionregion_idcn-shanghai
)search_face_request SearchFaceAdvanceRequest()
#场景一文件在本地
stream0 open(r/tmp/SearchFace.jpg, rb)
search_face_request.image_url_object stream0#场景二使用任意可访问的url
#url https://viapi-test-bj.oss-cn-beijing.aliyuncs.com/viapi-3.0domepic/facebody/SearchFace1.png
#img urlopen(url).read()
#search_face_request.image_url_object io.BytesIO(img)
search_face_request.db_name default
search_face_request.limit 5runtime_option RuntimeOptions()try:# 初始化Clientclient Client(config)response client.search_face_advance(search_face_request, runtime_option)# 获取整体结果print(response.body)except Exception as error:# 获取整体报错信息print(error)# 获取单个字段print(error.code)# tips: 可通过error.__dict__查看属性名称#关闭流
#stream0.close()一般比对成功的Python字典数据里的score会有大于0.6的值而比对失败score普遍低于0.1。 例如下面是比对成功的数据
{Data: {MatchList: [{FaceItems: [{Confidence: 80.54945, DbName:
default, EntityId: sfms, FaceId: 88665949, Score:
0.7572572231292725}, {Confidence: 77.51004, DbName: default, EntityId:
sfms, FaceId: 88665951, Score: 0.7193253040313721}, {Confidence:
74.420425, DbName: default, EntityId: sfms, FaceId: 88665946,
Score: 0.6665557622909546}, {Confidence: 11.461451, DbName: default,
EntityId: lyf, FaceId: 88657431, Score: 0.0663260966539383},
{Confidence: 5.28706, DbName: default, EntityId: lyf, FaceId:
88657429, Score: 0.030595608055591583}], Location: {Height: 527, Width:
405, X: 136, Y: 123}, QualitieScore: 99.3521}]}, RequestId: 6DE302BB-
130A-5D3C-B83D-0937D5A257FD}比对失败的数据则如下所示
{Data: {MatchList: [{FaceItems: [{Confidence: 6.137868, DbName:
default, EntityId: lyf, FaceId: 88657429, Score:
0.03551913797855377}, {Confidence: 2.9869182, DbName: default, EntityId:
lyf, FaceId: 88657433, Score: 0.017284952104091644}, {Confidence:
2.0808065, DbName: default, EntityId: lyf, FaceId: 88657431, Score:
0.01204138807952404}, {Confidence: 0.71279377, DbName: default, EntityId:
lyf, FaceId: 88657430, Score: 0.004124855622649193}, {Confidence: 0.0,
DbName: default, EntityId: sfms, FaceId: 88665951, Score:
-0.09112970530986786}], Location: {Height: 257, Width: 173, X: 156, Y:
42}, QualitieScore: 99.673065}]}, RequestId: 62C20100-CCAC-5FE2-9BA6-
AE583F0056EF}因此就可以利用获取的最大score的值判断是否大于0.6来判断是否比对成功。 返回数据的说明
Data这是一个对象其中包含了匹配列表的信息。
MatchList这是一个数组其中包含了匹配的结果。每个元素都是一个对象代表一个匹配项。
FaceItems这是一个数组其中包含了匹配项中所有人脸的信息。每个元素都是一个对象包含了一些关于
该人脸的信息如自信度Confidence、数据库名DbName、实体IDEntityId、面部ID
FaceId和分数Score。
Location这是一个对象包含了人脸在原始图像中的位置信息包括宽度Width、高度Height、
左上角的x坐标X和y坐标Y。
QualitieScore这是一个浮点数表示了整个匹配过程的质量得分。二、C语言调用阿里云人脸识别接口
修改上一小节的face.py代码将其中的代码封装成函数并获取其中字典里score的最大值以备C语言 调用
# -*- coding: utf-8 -*-
# 引入依赖包
# pip install alibabacloud_facebody20191230import os
import io
from urllib.request import urlopen
from alibabacloud_facebody20191230.client import Client
from alibabacloud_facebody20191230.models import SearchFaceAdvanceRequest
from alibabacloud_tea_openapi.models import Config
from alibabacloud_tea_util.models import RuntimeOptionsconfig Config(# 创建AccessKey ID和AccessKey Secret请参考https://help.aliyun.com/document_detail/175144.html。# 如果您用的是RAM用户的AccessKey还需要为RAM用户授予权限AliyunVIAPIFullAccess请参考https://help.aliyun.com/document_detail/145025.html。# 从环境变量读取配置的AccessKey ID和AccessKey Secret。运行代码示例前必须先配置环境变量。access_key_idos.environ.get(ALIBABA_CLOUD_ACCESS_KEY_ID),access_key_secretos.environ.get(ALIBABA_CLOUD_ACCESS_KEY_SECRET),# 访问的域名endpointfacebody.cn-shanghai.aliyuncs.com,# 访问的域名对应的regionregion_idcn-shanghai
)def alibaba_face():search_face_request SearchFaceAdvanceRequest()#场景一文件在本地stream0 open(r/tmp/SearchFace.jpg, rb)search_face_request.image_url_object stream0#场景二使用任意可访问的url#url https://viapi-test-bj.oss-cn-beijing.aliyuncs.com/viapi-3.0domepic/facebody/SearchFace1.png#img urlopen(url).read()#search_face_request.image_url_object io.BytesIO(img)search_face_request.db_name defaultsearch_face_request.limit 5runtime_option RuntimeOptions()try:# 初始化Clientclient Client(config)response client.search_face_advance(search_face_request, runtime_option)# 获取整体结果match_list response.body.to_map()[Data][MatchList]scores [item[Score] for item in match_list[0][FaceItems]]highest_score max(scores)value round(highest_score, 2)return valueexcept Exception as error:# 获取整体报错信息print(error)# 获取单个字段print(error.code)return 0.0# tips: 可通过error.__dict__查看属性名称#关闭流stream0.close()if __name__ __main__:alibaba_face()这里面对scores [item[Score] for item in match_list[0][FaceItems]] 的解释
match_list[0][FaceItems]]输入内容为
[{Confidence: 12.260886, DbName: default, EntityId: sfms, FaceId:
88665949, Score: 0.07095234096050262}, {Confidence: 9.446312, DbName:
default, EntityId: sfms, FaceId: 88665946, Score:
0.054664719849824905}, {Confidence: 1.2030103, DbName: default, EntityId:
sfms, FaceId: 88665951, Score: 0.006961682811379433}, {Confidence: 0.0,
DbName: default, EntityId: lyf, FaceId: 88657431, Score:
-0.03559441864490509}, {Confidence: 0.0, DbName: default, EntityId:
lyf, FaceId: 88657429, Score: -0.04274216294288635}]
那么[item[Score] for item in match_list[0][FaceItems]是一个 Python 列表推导式
用于从嵌套的字典中提取特定的值。
具体来说match_list 是一个包含字典的列表。每个字典里都有很多键值对其中一个键是
FaceItems。FaceItems 对应的值是一个字典列表每个字典都代表一个面部信息并且都有一个
Score 键。
这个列表推导式的目的是从 data 的第一个元素即第一个字典中的 FaceItems 键对应的字典列表中
提取所有 Score 键的值并将这些值存储在一个新的列表 scores 中。
分解一下这个列表推导式
for item in data[0][FaceItems]这部分代码遍历 match_list 的第一个元素中的
FaceItems 键对应的字典列表。在每次循环中item 被赋予列表中的下一个字典。
item[Score]这部分代码获取当前 item即一个包含面部信息的字典中 Score 键对应的值。
[item[Score] for item in data[0][FaceItems]]整体而言这个列表推导式创建一个新的列
表 scores该列表包含 data 中第一个元素的 FaceItems 键对应的所有字典的 Score 键的值。
最终scores 将是一个包含所有 Score 值的列表你可以对这个列表进行进一步的操作和分析比如找
出最大值。三、System V消息队列和POSIX 消息队列
在后面的项目中会用POSIX消息队列 和System V消息队列msgget、msgsnd msgrcv 类似都是用以队列的形式传递消息。接口主要有以下几个 System V消息队列POSIX 消息队列主要函数 1. 创建或获取消息队列 msgget(key_t key, int oflag) 2. 往消息队列中放入消息 msgsnd(int msqid, const void *ptr, size_t length, int flag) 3. 从消息队列中读取消息 msgrcv(int msqid, void *ptr, size_t length, long type, int flag) 4. 控制消息队列 msgctl(int msqid, int cmd, struct msqid_ds *buf) 1. 创建或打开消息队列 mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr attr ); 2. 发送消息到消息队列 int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio) 3. 从消息队列接收消息 ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio) 4. 关闭一个消息队列 int mq_close(mqd_t mqdes) 5. 删除一个消息队列 int mq_unlink(const char *name) 6. 注册消息队列的异步通知 int mq_notify(mqd_t mqdes,const struct sigevent *notification); 7. 获取消息队列的属性 int mq_getattr(mqd_t mqdes, struct mq_attr *attr); 8. 设置消息队列的属性 int mq_setattr(mqd_t mqdes, struct mq_attr *attr, struct mq_attr *oattr); 基本用法 1.创建或获取消息队列 使用msgget()函数来创建或获取一个消息队列。该函数接受一个键key和一个标志flag作为参数。如果键的值为IPC_PRIVATE或当前没有消息队列与给定键相关联将会创建一个新的消息队列。标志位可以用来指定权限组合。 2. 往消息队列中放入消息 使用msgsnd()函数来往一个消息队列中放入一个消息。该函数接受四个参数分别为消息队列标识符、指向消息的指针、消息的大小以及标志位。成功放入消息后该函数返回0否则返回-1并设置errno来表示错误原因。 3. 从消息队列中读取消息 使用msgrcv()函数来从一个消息队列中读取一个消息。该函数接受五个参数分别为消息队列标识符、指向消息的指针、消息的最大大小、消息的类型以及标志位。成功读取消息后该函数返回读取到的消息的大小否则返回-1并设置errno来表示错误原因。 4. 控制消息队列 使用msgctl()函数来对一个消息队列进行控制操作如删除、设置权限等。该函数接受三个参数分别为消息队列标识符、操作命令以及一个可选的参数。 1.创建或打开消息队列 使用mqd_t mq_open(const char *name,int oflag,mode_t mode,struct mq_attr *attr);函数来创建或打开一个消息队列。该函数接受队列名称、打开标志以及可选的权限和属性作为参数。如果队列不存在且指定了创建标志将会创建一个新的消息队列。成功创建或打开后函数返回一个消息队列描述符mqd_t。 2. 发送消息 使用int mq_send(mqd_t mqdes,const char *msg_ptr,size_t msg_len,unsigned int msg_prio);函数来发送一个消息到指定的消息队列。该函数接受消息队列描述符、指向消息的指针以及消息的大小作为参数。发送消息时可以指定消息的优先级较高的优先级数值表示较高的优先级。成功发送后函数返回0否则返回-1并设置errno来表示错误原因。 3. 接收消息 使用ssize_t mq_receive(mqd_t mqdes, char *mdg_ptr,size_t msg_len,unsigned int *msg_prio);函数来从指定的消息队列中接收一个消息。该函数接受消息队列描述符、指向接收缓冲区的指针以及缓冲区的最大大小作为参数。接收消息时可以选择按优先级接收也可以选择非阻塞接收。成功接收后函数返回接收到的消息的大小否则返回-1并设置errno来表示错误原因。 4. 关闭消息队列 使用int mq_close(mqd_t mqdes);函数来关闭一个已打开的消息队列。该函数接受消息队列描述符作为参数。关闭消息队列后相关的资源将被释放。 5. 删除消息队列 使用int mq_unlink(const char *name);函数来删除一个已存在的消息队列。该函数接受队列名称作为参数。删除一个消息队列将会移除与之关联的所有消息和状态。 2、3步可以改成下面的6、7、8步支持异步通知: 6. 设置异步通知 使用int mq_notify(mqd_t mqdes,const struct sigevent *notification);函数来注册一个进程以接收异步通知。该函数接受消息队列描述符、一个指向sigevent结构的指针以及一个通知标志作为参数。在sigevent结构中可以设置当消息到达时要发送的信号或者要调用的回调函数。通过设置用int mq_notify(mqd_t mqdes,const struct sigevent *notification);当消息队列从空变为非空时已注册的进程将收到一个信号或触发一个回调函数以异步地通知该进程。 7. 发送消息 使用int mq_send(mqd_t mqdes,const char *msg_ptr,size_t msg_len,unsigned int msg_prio);函数来发送一个消息到指定的消息队列。该函数接受消息队列描述符、指向消息的指针以及消息的大小作为参数。发送消息时可以指定消息的优先级较高的优先级数值表示较高的优先级。成功发送后函数返回0否则返回-1并设置errno来表示错误原因。 8.处理异步通知 当有新消息到达时已注册的进程将收到一个信号或触发一个回调函数。在信号处理函数或回调函数中可以执行相关的操作来处理新到达的消息。例如可以调用ssize_t mq_receive(mqd_t mqdes, char *mdg_ptr,size_t msg_len,unsigned int *msg_prio);来接收并处理消息。
其他说明
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr) 中oflag和 mode 参数说明 参数oflag同int open(const char *pathname, int flags, mode_t mode);函数的的oflag类似有 O_RDONLY、O_RDWR O_WRONLY除此之外还有 O_CREAT、O_EXCL如果 O_CREAT 指定但 name 不存在就返回错误O_NONBLOCK以非阻塞方式打开消息队列在正常情况下 mq_receive和mq_send 函数会阻塞的地方使用该标志打开的消息队列会返回 EAGAIN 错误。 参数mode同int open(const char *pathname, int flags, mode_t mode);函数的mode参数用于指定 权限位 比如0644权限关于 struct mq_attr属性结构提
struct mq_attr
{long mq_flags;//阻塞标志 0(阻塞)或O_NONBLOCKlong mq_maxmsg;//最大消息数long mq_msgsize;//每个消息最大大小long mq_curmsgs;//当前消息数
};mq_notiy函数的使用注意事项 a. 注册撤销当通知被发送给它的注册进程时其注册会被撤销。这意味着如果希望继续接收通知 进程必须再次调用 mq_notify 以重新注册。 b. 空队列与数据到来消息机制触发条件是在消息队列为空的情况下有数据到来才会触发。当消息队 列不为空时即使有新的数据到来也不会触发通知。 c. 阻塞与通知只有当没有任何线程阻塞在该队列的 mq_receive 调用的前提下通知才会发出。这意 味着如果有线程正在等待接收消息通知可能不会被发送。struct sigevent和sigval_t sigev_val 的定义如下
union sigval { /* Data passed with notification */int sival_int; /* Integer value */void *sival_ptr; /* Pointer value */
};struct sigevent {int sigev_notify; /* Notification method */int sigev_signo; /* Notification signal */union sigval sigev_value;/* Data passed with notification */void (*sigev_notify_function) (union sigval);/* Function used for threadnotification (SIGEV_THREAD) */void *sigev_notify_attributes;/* Attributes for notification thread(SIGEV_THREAD) */pid_t sigev_notify_thread_id;/* ID of thread to signal(SIGEV_THREAD_ID); Linux-specific */
};a. sigev_notify取值 SIGEV_NONE这个值表示不需要任何通知。当sigev_notify被设置为这个值时即使事件发生了也不会有任何通知发送到进程。 SIGEV_SIGNAL事件发生时将sigev_signo指定的信号发送给指定的进程 SIGEV_THREAD事件发生时内核会在此进程内以sigev_notify_attributes为线程属性创建一个线程并让其执行sigev_notify_function并以sigev_value为其参数 b. sigev_signo: 在sigev_notifySIGEV_SIGNAL时使用指定信号类别, 例如SIGUSR1、SIGUSR2 等 c.sigev_value: sigev_notifySIGEV_SIGEV_THREAD时使用作为sigev_notify_function的参数, 当发送信号时,这个值会传递给信号处理函数。
示例1:使用阻塞方式读写
// 包含所需的头文件
#include pthread.h // POSIX线程库
#include stdio.h // 标准输入输出库
#include stdlib.h // 标准库
#include unistd.h // UNIX标准库
#include mqueue.h // POSIX消息队列库
#include string.h // 字符串处理库// 定义消息队列的名称和要发送的消息
#define QUEUE_NAME /test_queue // 消息队列的名称
#define MESSAGE Hello, World! // 要发送的消息// 全局的消息队列描述符
mqd_t mq;// sender_thread函数发送线程的主体
void *sender_thread(void *arg) {char message[] MESSAGE; // 创建要发送的消息的副本printf(Sender thread started.\n); // 打印发送线程开始的消息mq_send(mq, message, strlen(message) 1, 0); // 发送消息到消息队列printf(Message sent.\n); // 打印消息已发送的消息return NULL; // 返回NULL表示线程正常结束
}// receiver_thread函数接收线程的主体
void *receiver_thread(void *arg) {char buffer[256]; // 创建用于接收消息的缓冲区printf(Receiver thread started.\n); // 打印接收线程开始的消息mq_receive(mq, buffer, sizeof(buffer), NULL); // 从消息队列接收消息printf(Received message: %s\n, buffer); // 打印已接收的消息return NULL; // 返回NULL表示线程正常结束
}// main函数程序的入口点
int main() {pthread_t sender, receiver; // 创建发送和接收线程的标识符struct mq_attr attr; // 创建消息队列属性结构体变量// 设置消息队列的属性值attr.mq_flags 0; // 消息队列的标志位设置为0attr.mq_maxmsg 10; // 消息队列的最大消息数设置为10attr.mq_msgsize 256; // 消息队列的每个消息的最大大小设置为256字节attr.mq_curmsgs 0; // 消息队列的当前消息数设置为0// 打开或创建名为QUEUE_NAME的消息队列并设置其属性为attr指定的值mq mq_open(QUEUE_NAME, O_CREAT | O_RDWR, 0666, attr);if (mq (mqd_t)-1) { // 如果打开或创建失败则打印错误信息并返回1perror(mq_open);return 1;}// 创建发送线程如果创建失败则打印错误信息并返回1if (pthread_create(sender, NULL, sender_thread, NULL) ! 0) {perror(pthread_create (sender));return 1;}// 创建接收线程如果创建失败则打印错误信息并返回1if (pthread_create(receiver, NULL, receiver_thread, NULL) ! 0) {perror(pthread_create (receiver));return 1;}// 等待发送线程结束如果发送线程已经结束则立即返回否则阻塞等待其结束pthread_join(sender, NULL);// 等待接收线程结束如果接收线程已经结束则立即返回否则阻塞等待其结束pthread_join(receiver, NULL);// 关闭已打开的消息队列描述符mq所引用的消息队列并释放由该描述符占用的所有资源mq_close(mq);// 删除名为QUEUE_NAME的消息队列并将其从系统中删除如果成功则返回0否则返回-1并设置errno以指示错误。mq_unlink(QUEUE_NAME); // 删除消息队列return 0; // 程序正常退出返回0
}示例2 使用mq_notify sigev_notify SIGEV_THREAD异步通知的方式实现
#include mqueue.h
#include pthread.h
#include stdio.h
#include errno.h
#include string.h
#include unistd.h
#include stdlib.h
#include signal.h#if 0
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr attr );
int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio); /tiemou
ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *prio);
int mq_close(mqd_t mqdes);
int mq_unlink(const char *name)struct mq_attr
{long mq_flags;//阻塞标志 0(阻塞)或O_NONBLOCKlong mq_maxmsg;//最大消息数long mq_msgsize;//每个消息最大大小long mq_curmsgs;//当前消息数
};union sigval { /* Data passed with notification */int sival_int; /* Integer value */void *sival_ptr; /* Pointer value */
};struct sigevent {int sigev_notify; /* Notification method */int sigev_signo; /* Notification signal */union sigval sigev_value;/* Data passed with notification */void (*sigev_notify_function) (union sigval);/* Function used for threadnotification (SIGEV_THREAD) */void *sigev_notify_attributes;/* Attributes for notification thread(SIGEV_THREAD) */pid_t sigev_notify_thread_id;/* ID of thread to signal(SIGEV_THREAD_ID); Linux-specific */
};#endif#define QUEQUE_NAME /test_queue
#define MESSAGE mqueque,test!void *sender_thread(void *arg)
{// 发送消息mqd_t mqd *(mqd_t *)arg;int send_size -1;char message[] MESSAGE;printf(sender thread message%s, mqd%d\n, message, mqd);send_size mq_send(mqd, message, strlen(message) 1, 0);if (-1 send_size){if (errno EAGAIN){printf(message queque is full\n);}else{perror(mq_send);}}return NULL;
}void notify_thread (union sigval sval)
{// 获取消息队列描述符mqd_t mqd -1;mqd *((mqd_t *)sval.sival_ptr);// 定义一个缓冲区用于存储接收到的消息char buffer[256];// 定义一个变量用于存储接收到的消息的大小ssize_t bytes_read;// 定义一个结构体用于重新注册消息队列的通知struct sigevent sev;// 打印提示信息printf(notify_thread started, mqd%d\n, mqd);// 循环接收消息直到队列为空while (1){// 从消息队列中接收消息bytes_read mq_receive(mqd, buffer, 256, NULL);// 如果接收失败检查错误码if (bytes_read -1){// 如果错误码是EAGAIN说明队列为空跳出循环if (errno EAGAIN){printf(queue is empty\n);break;}// 否则打印错误信息退出程序else{perror(mq_receive);exit(1);}}// 如果接收成功打印接收到的消息的大小和内容printf(read %ld bytes: %s\n, (long)bytes_read, buffer);}// 重新注册消息队列的通知使用同样的回调函数和参数sev.sigev_notify SIGEV_THREAD;sev.sigev_notify_function notify_thread;sev.sigev_notify_attributes NULL;sev.sigev_value.sival_ptr mqd;if (mq_notify(mqd, sev) -1){perror(mq_notify);exit(1);}
}#if 0
void *receiver_thread(void *arg)
{mqd_t mqd *(mqd_t *)arg;ssize_t receiver_size -1;//接收消息char buffer[256];printf(Receive trehad start\n);receiver_size mq_receive(mqd, buffer, sizeof(buffer), NULL);printf(receiver thread message%s, mqd%d, receiver_size%ld\n, buffer, mqd, receiver_size);return NULL;
}
#endifint main(int argc, char *argv[])
{pthread_t sender, receiver;//创建消息队列mqd_t mqd -1;struct mq_attr attr;attr.mq_flags 0;attr.mq_maxmsg 10;attr.mq_msgsize 256;attr.mq_curmsgs 0;mqd mq_open(QUEQUE_NAME, O_CREAT | O_RDWR, 0666, attr);if (mqd (mqd_t)-1 ){perror(mq_open);return -1;}struct sigevent sev;// 注册消息队列的通知使用线程模式指定回调函数和参数sev.sigev_notify SIGEV_THREAD;sev.sigev_notify_function notify_thread;sev.sigev_notify_attributes NULL;sev.sigev_value.sival_ptr mqd;if (mq_notify(mqd, sev) -1){perror(mq_notify);exit(1);}if (pthread_create(sender, NULL, sender_thread, (void *)mqd) ! 0){perror(pthread_create sender);return -1;}#if 0if (pthread_create(receiver, NULL, receiver_thread, (void *)mqd) ! 0){perror(pthread_create receiver);return -1;}
#endifpthread_join(sender, NULL);sleep(5);//等待触发并把消息读走//pthread_join(receiver, NULL);mq_close(mqd);mq_unlink(QUEQUE_NAME);//sleep(5);return 0;
}