基于OpenHarmony标准系统的C++公共基础类库案例:Semaphore
liebian365 2025-01-02 17:42 19 浏览 0 评论
1、程序简介
该程序是基于OpenHarmony标准系统的C++公共基础类库的线程处理:Sempahore。
本案例完成如下工作:
(1)无名信号量使用方法
- 定义1个无名信号量,1个供无名信号量管理的公共资源变量;
- 创建5个线程,每个线程做5次for循环,for循环的内容是获取无名信号量,并修改公共资源变量;
(2)有名信号量使用方法
- 定义1个有名信号量,1个供有名信号量管理的公共资源变量;
- 创建1个线程A,通过Open获取信号量,做5次for循环,for循环的内容是通过Wait获取有名信号量,如果获取成功则修改公共资源变量(即累加1),最后释放信号量;
- 创建1个线程B,通过Open获取信号量,做5次for循环,for循环的内容是通过TryWait获取有名信号量,如果获取成功则修改公共资源变量(即累加10),最后释放信号量;
- 创建1个线程C,通过Open获取信号量,做5次for循环,for循环的内容是通过TimedWait获取有名信号量,如果获取成功则修改公共资源变量(即累加100),最后释放信号量;
2、基础知识
C++公共基础类库为标准系统提供了一些常用的C++开发工具类,包括:
- 文件、路径、字符串相关操作的能力增强接口
- 读写锁、信号量、定时器、线程增强及线程池等接口
- 安全数据容器、数据序列化等接口
- 各子系统的错误码相关定义
2.1、添加C++公共基础类库依赖
修改需调用模块的BUILD.gn,在external_deps或deps中添加如下:
ohos_shared_library("xxxxx") {
...
external_deps = [
...
# 动态库依赖(可选)
"c_utils:utils",
# 静态库依赖(可选)
"c_utils:utilsbase",
# Rust动态库依赖(可选)
"c_utils:utils_rust",
]
...
}
一般而言,我们只需要填写"c_utils:utils"即可。
2.2、Semaphore头文件
C++公共基础类库的Semaphore头文件在://commonlibrary/c_utils/base/include/semaphore_ex.h
可在源代码中添加如下:
#include <semaphore_ex.h>
OpenHarmony信号量根据种类可以分为有名信号量和无名信号量,所以命令空间如下:
(1)无名信号量命名空间
OHOS::Semaphore
(2)有名信号量命名空间
OHOS::NamedSemaphore
2.3、OHOS::Samaphore接口说明
Semaphore为无名信号量。
2.3.1、Samaphore
构造函数, 构造一个Samaphore对象。
Semaphore(int value = 1);
参数说明:
参数名称 | 类型 | 参数说明 |
value | int | 信号量当前资源数量 |
2.3.2、~Semaphore
析构函数。
~Semaphore();
2.3.3、Wait
等待/获取信号量(即信号量 -1)。
void Wait();
2.3.4、Post
释放信号量(即信号量 +1)。
void Post();
2.4、OHOS::NamedSemaphore接口说明
NamedSemaphore为有名信号量。
2.4.1、NamedSemaphore
构造函数, 构造NamedSemaphore对象。
NamedSemaphore(size_t size)
NamedSemaphore(const std::string& name, size_t size)
参数说明:
参数名称 | 类型 | 参数说明 |
name | std::string | 信号量名称 |
size | size_t | 信号量有效资源数量 |
2.4.2、~NamedSemaphore
析构函数。
~NamedSemaphore();
2.4.3、Create
创建并初始化有名信号量。
bool Create();
返回值说明:
类型 | 返回值说明 |
bool | true表示成功,false表示失败 |
2.4.4、Unlink
将有名信号量文件从系统中删除。
bool Unlink();
返回值说明:
类型 | 返回值说明 |
bool | true表示成功,false表示失败 |
2.4.5、Open
打开一个已经创建的有名信号量文件。
bool Open();
返回值说明:
类型 | 返回值说明 |
bool | true表示成功,false表示失败 |
2.4.6、Close
关闭有名信号量。
bool Close();
返回值说明:
类型 | 返回值说明 |
bool | true表示成功,false表示失败 |
2.4.7、Wait
等待/获取信号量(信号量 -1)。
bool Wait();
返回值说明:
类型 | 返回值说明 |
bool | true表示成功,false表示失败 |
2.4.8、TryWait
等待/获取信号量(信号量 -1)的接口;非阻塞版。
bool TryWait();
返回值说明:
类型 | 返回值说明 |
bool | true表示成功,false表示失败 |
2.4.9、TimedWait
等待/获取信号量(信号量 -1);指定阻塞时间版。
bool TimedWait(const struct timespec& ts);
参数说明:
参数名称 | 类型 | 参数说明 |
ts | struct timespec | 绝对时间。注意:ts是utc时间,不是相对时间。 |
返回值说明:
类型 | 返回值说明 |
bool | true表示成功,false表示失败 |
2.4.10、Post
释放信号量(信号量 +1)。
bool Post();
返回值说明:
类型 | 返回值说明 |
bool | true表示成功,false表示失败 |
2.4.10、GetValue
获取信号的值。
int GetValue() const;
返回值说明:
类型 | 返回值说明 |
int | 返回当前信号量的值 |
3、程序解析
3.1、创建编译引导
在//vendor/lockzhiner/rk3568/samples/BUILD.gn文件添加一行编译引导语句。
import("//build/ohos.gni")
group("samples") {
deps = [
"a24_utils_semaphore:utils_semaphore", # 添加该行
]
}
"a24_utils_semaphore:utils_semaphore",该行语句表示引入参与编译。
3.2、创建编译项目
创建a24_utils_semaphore目录,并添加如下文件:
a24_utils_semaphore
├── utils_name_semaphore.cpp # 有名信号量案例
├── utils_noname_semaphore.cpp # 无名信号量案例
├── BUILD.gn # GN文件
3.3、创建BUILD.gn
编辑BUILD.gn文件。
添加2个可执行程序,分别是:
- utils_noname_semaphore:无名信号量使用案例
- utils_name_semaphore:有名信号量使用案例
import("//build/ohos.gni")
ohos_executable("utils_noname_semaphore") {
sources = [ "utils_noname_semaphore.cpp" ]
include_dirs = [
"//commonlibrary/c_utils/base/include",
"//commonlibrary/c_utils/base:utils",
"//third_party/googletest:gtest_main",
"//third_party/googletest/googletest/include",
]
external_deps = [ "c_utils:utils" ]
part_name = "product_rk3568"
install_enable = true
}
ohos_executable("utils_name_semaphore") {
sources = [ "utils_name_semaphore.cpp" ]
include_dirs = [
"//commonlibrary/c_utils/base/include",
"//commonlibrary/c_utils/base:utils",
"//third_party/googletest:gtest_main",
"//third_party/googletest/googletest/include",
]
external_deps = [ "c_utils:utils" ]
part_name = "product_rk3568"
install_enable = true
}
group("utils_semaphore") {
deps = [
":utils_noname_semaphore",
":utils_name_semaphore",
]
}
注意:
(1)BUILD.gn中所有的TAB键必须转化为空格,否则会报错。如果自己不知道如何规范化,可以:
# 安装gn工具
sudo apt-get install ninja-build
sudo apt install generate-ninja
# 规范化BUILD.gn
gn format BUILD.gn
3.4、无名信号量使用案例
3.4.1、添加信号量头文件
#include <semaphore_ex.h>
3.4.2、创建无名信号量以及公共资源变量
static int m_count = 0; // 公共资源变量
static OHOS::Semaphore m_sem(1); // 无名信号量
3.4.3、创建线程池
OHOS::ThreadPool threads("noname_semaphore_threads");
3.4.4、设置线程池
OHOS::ThreadPool threads("noname_semaphore_threads");
3.4.5、启动线程
for (int i = 0; i < threads_start; i++) {
string str_name = "thread_" + to_string(i);
auto task = std::bind(func, str_name);
threads.AddTask(task);
sleep(1);
}
3.4.6、编写子线程代码
循环5次,每次循环调用信号量Wait()等待获取信号量。如果获取信号量后,将公共资源变量累加,调用信号量Post()释放信号量。
void func(const string &name)
{
for (int i = 0; i < 5; i++) {
cout << name << ": Sema Wait..." << endl;
m_sem.Wait();
cout << name << ": Sema Wait Successful" << endl;
m_count += 1;
m_sem.Post();
cout << name << ": Sema Post" << endl;
sleep(1);
}
}
3.5、有名信号量使用案例
3.5.1、添加信号量头文件
#include <semaphore_ex.h>
3.5.2、创建有名信号量
首先定义有名信号量,然后通过Create()创建全局有名信号量。
int main(int argc, char **argv)
{
OHOS::NamedSemaphore sem(STRING_NAME_SEMAPHORE, 1);
......
if (!sem.Create()) {
cout << "NamedSemaphore.Create() failed\n";
return -1;
}
......
}
3.5.3、创建线程池
通过OHOS::ThreadPool定义线程池,调用SetMaxTaskNum()设置线程池最大线程数,并调用Start()设置当前启动多少个线程。
int main(int argc, char **argv)
{
OHOS::ThreadPool threads("name_semaphore_threads");
int threads_start = 3;
......
threads.SetMaxTaskNum(128);
threads.Start(threads_start);
......
}
3.5.4、启动子线程A、B和C
int main(int argc, char **argv)
{
......
// 启动线程A
str_name = "thread_a";
auto task_a = std::bind(funcA, str_name);
threads.AddTask(task_a);
// 启动线程B
str_name = "thread_b";
auto task_b = std::bind(funcB, str_name);
threads.AddTask(task_b);
// 启动线程A
str_name = "thread_c";
auto task_c = std::bind(funcC, str_name);
threads.AddTask(task_c);
threads.Stop();
cout << "threads stop" << endl;
return 0;
}
3.5.5、编写子线程A
首先定义有名信号量,信号量数目可以随意设置。
其次,通过Open()打开有名信号量,可以与main()的有名信号量共享同一个信号量。
最后,通过Wait()和Post()来获取释放信号量。
static void funcA(const string &name)
{
OHOS::NamedSemaphore sem(STRING_NAME_SEMAPHORE, 1);
cout << get_curtime() << ", " << name << ": start\n";
// 打开一个已经创建的有名信号量文件
if (!sem.Open()) {
cout << get_curtime() << ", " << name << ": sema open failed" << endl;
return;
}
for (int i = 0; i < 5; i++) {
cout << get_curtime() << ", " << name << ": sema wait..." << endl;
sem.Wait();
cout << get_curtime() << ", " << name << ": sema wait success" << endl;
m_count += 1;
usleep(1000 * 1000 * 1);
cout << get_curtime() << ", " << name << ": sema count = " << m_count << endl;
sem.Post();
cout << get_curtime() << ", " << name << ": sema post and sleep 1 sec" << endl;
sleep(1);
}
cout << get_curtime() << ", " << name << ": end" << endl;
}
3.5.6、编写子线程B
首先定义有名信号量,信号量数目可以随意设置。
其次,通过Open()打开有名信号量,可以与main()的有名信号量共享同一个信号量。
最后,通过TryWait()和Post()来获取释放信号量。
static void funcB(const string &name)
{
OHOS::NamedSemaphore sem(STRING_NAME_SEMAPHORE, 1);
cout << get_curtime() << ", " << name << ": start\n";
// 打开一个已经创建的有名信号量文件
if (!sem.Open()) {
cout << get_curtime() << ", " << name << ": sema open failed" << endl;
return;
}
for (int i = 0; i < 5; i++) {
cout << get_curtime() << ", " << name << ": sema trywait..." << endl;
if (sem.TryWait()) {
cout << get_curtime() << ", " << name << ": sema trywait success" << endl;
m_count += 10;
usleep(1000 * 1000 * 1);
cout << get_curtime() << ", " << name << ": sema count = " << m_count << endl;
sem.Post();
cout << get_curtime() << ", " << name << ": sema post and sleep 1 sec" << endl;
} else {
cout << get_curtime() << ", " << name << ": sema tryWait failed and sleep 1 sec" << endl;
}
sleep(1);
}
cout << get_curtime() << ", " << name << ": end" << endl;
}
3.5.7、编写子线程C
首先定义有名信号量,信号量数目可以随意设置。
其次,通过Open()打开有名信号量,可以与main()的有名信号量共享同一个信号量。
最后,通过TimedWait()和Post()来获取释放信号量。
static void funcC(const string &name)
{
OHOS::NamedSemaphore sem(STRING_NAME_SEMAPHORE, 1);
struct timespec ts;
cout << get_curtime() << ", " << name << ": start\n";
// 打开一个已经创建的有名信号量文件
if (!sem.Open()) {
cout << get_curtime() << ", " << name << ": sema open failed" << endl;
return;
}
for (int i = 0; i < 5; i++) {
clock_gettime(CLOCK_REALTIME, &ts);
// 超时等待时间,1秒
ts.tv_sec += 1;
cout << get_curtime() << ", " << name << ": sema timedwait 1 sec..." << endl;
if (sem.TimedWait(ts)) {
cout << get_curtime() << ", " << name << ": sema timedwait success" << endl;
m_count += 100;
usleep(1000 * 100);
cout << get_curtime() << ", " << name << ": sema count = " << m_count << endl;
sem.Post();
cout << get_curtime() << ", " << name << ": sema post" << endl;
} else {
cout << get_curtime() << ", " << name << ": sema timedwait failed and sleep 1 sec" << endl;
sleep(1);
}
}
cout << get_curtime() << ", " << name << ": end" << endl;
}
4、编译步骤
进入OpenHarmony编译环境,运行如下命令:
hb build -f
将镜像烧录到开发板中。
5、运行结果
5.1、无名信号量
运行结果如下:
# utils_noname_semaphore
thread_0: Sema Wait...
thread_0: Sema Wait Successful
thread_0: Sema Post
thread_1: Sema Wait...
thread_1: Sema Wait Successful
thread_1: Sema Post
thread_0: Sema Wait...
thread_0: Sema Wait Successful
thread_0: Sema Post
thread_2: Sema Wait...
thread_2: Sema Wait Successful
thread_2: Sema Post
thread_0: Sema Wait...
thread_0: Sema Wait Successful
thread_0: Sema Post
thread_1: Sema Wait...
thread_1: Sema Wait Successful
thread_1: Sema Post
thread_3: Sema Wait...
thread_3: Sema Wait Successful
thread_3: Sema Post
thread_2: Sema Wait...
thread_0: Sema Wait Successful
thread_2: Sema Wait...
thread_2: Sema Post
thread_1: Sema Wait...
thread_0: Sema Wait Successful
thread_0: Sema Post
thread_1: Sema Wait Successful
thread_1: Sema Post
thread_4: Sema Wait...
thread_4: Sema Wait Successful
thread_4: Sema Post
thread_3: Sema Wait...
thread_3: Sema Wait Successful
thread_3: Sema Post
thread_2: Sema Wait...
thread_2: Sema Wait Successful
thread_2: Sema Post
thread_0: Sema Wait...
thread_0: Sema Wait Successful
thread_0: Sema Post
thread_1: Sema Wait...
thread_1: Sema Wait Successful
thread_1: Sema Post
thread_4: Sema Wait...
thread_4: Sema Wait Successful
thread_4: Sema Post
thread_3: Sema Wait...
thread_3: Sema Wait Successful
thread_3: Sema Post
thread_2: Sema Wait...
thread_2: Sema Wait Successful
thread_2: Sema Post
thread_1: Sema Wait...
thread_1: Sema Wait Successful
thread_1: Sema Post
thread_4: Sema Wait...
thread_4: Sema Wait Successful
thread_4: Sema Post
thread_3: Sema Wait...
thread_3: Sema Wait Successful
thread_3: Sema Post
thread_2: Sema Wait...
thread_2: Sema Wait Successful
thread_2: Sema Post
thread_4: Sema Wait...
thread_4: Sema Wait Successful
thread_4: Sema Post
thread_3: Sema Wait...
thread_3: Sema Wait Successful
thread_3: Sema Post
thread_4: Sema Wait...
thread_4: Sema Wait Successful
thread_4: Sema Post
threads stop
#
5.2、有名信号量
运行结果如下:
# utils_name_semaphore
2017-8-5 19:43:24, thread_a: start
2017-8-5 19:43:24, thread_b: start
2017-8-5 19:43:24, thread_c: start
2017-8-5 19:43:24, thread_a: sema wait...
2017-8-5 19:43:24, thread_a: sema wait success
2017-8-5 19:43:24, thread_b: sema trywait...
2017-8-5 19:43:24, thread_b: sema tryWait failed and sleep 1 sec
2017-8-5 19:43:24, thread_c: sema timedwait 1 sec...
2017-8-5 19:43:25, thread_a: sema count = 1
2017-8-5 19:43:25, thread_c: sema timedwait failed and sleep 1 sec
2017-8-5 19:43:25, thread_a: sema post and sleep 1 sec
2017-8-5 19:43:25, thread_b: sema trywait...
2017-8-5 19:43:25, thread_b: sema trywait success
2017-8-5 19:43:26, thread_a: sema wait...
2017-8-5 19:43:26, thread_c: sema timedwait 1 sec...
2017-8-5 19:43:26, thread_b: sema count = 11
2017-8-5 19:43:26, thread_b: sema post and sleep 1 sec
2017-8-5 19:43:26, thread_a: sema wait success
2017-8-5 19:43:27, thread_c: sema timedwait failed and sleep 1 sec
2017-8-5 19:43:27, thread_b: sema trywait...
2017-8-5 19:43:27, thread_b: sema tryWait failed and sleep 1 sec
2017-8-5 19:43:27, thread_a: sema count = 12
2017-8-5 19:43:27, thread_a: sema post and sleep 1 sec
2017-8-5 19:43:28, thread_c: sema timedwait 1 sec...
2017-8-5 19:43:28, thread_c: sema timedwait success
2017-8-5 19:43:28, thread_b: sema trywait...
2017-8-5 19:43:28, thread_a: sema wait...2017-8-5 19:43:28, thread_b
: sema tryWait failed and sleep 1 sec
2017-8-5 19:43:28, thread_c: sema count = 112
2017-8-5 19:43:28, thread_c: sema post
2017-8-5 19:43:28, thread_c: sema timedwait 1 sec...
2017-8-5 19:43:28, thread_a: sema wait success
2017-8-5 19:43:29, thread_b: sema trywait...
2017-8-5 19:43:29, thread_b: sema tryWait failed and sleep 1 sec
2017-8-5 19:43:29, thread_c: sema timedwait failed and sleep 1 sec
2017-8-5 19:43:29, thread_a: sema count = 113
2017-8-5 19:43:29, thread_a: sema post and sleep 1 sec
2017-8-5 19:43:30, thread_b: sema close
2017-8-5 19:43:30, thread_c: sema timedwait 1 sec...
2017-8-5 19:43:30, thread_c: sema timedwait success
2017-8-5 19:43:30, thread_a: sema wait...
2017-8-5 19:43:31, thread_c: sema count = 213
2017-8-5 19:43:31, thread_c: sema post
2017-8-5 19:43:31, thread_c: sema close
2017-8-5 19:43:31, thread_a: sema wait success
2017-8-5 19:43:32, thread_a: sema count = 214
2017-8-5 19:43:32, thread_a: sema post and sleep 1 sec
2017-8-5 19:43:33, thread_a: sema wait...
2017-8-5 19:43:33, thread_a: sema wait success
2017-8-5 19:43:34, thread_a: sema count = 215
2017-8-5 19:43:34, thread_a: sema post and sleep 1 sec
2017-8-5 19:43:35, thread_a: sema close
threads stop
#
- 上一篇:扒一扒鸿蒙中的Gn与Ninja
- 下一篇:鸿蒙开发从hello world开始
相关推荐
- python如何对字符串进行操作(python如何对字符串进行操作输出)
-
1.字符串的创建可通过直接赋值、构造或转义字符来创建字符串。#普通字符串s="Hello,World!"#多行字符串(使用三引号)multi_line_str='''Thisi...
- Excel表格中11个常用的字符串函数
-
今天和大家聊聊常用的字符串函数,在不同的条件下,如何选择字符串函数很关键。下面我为大家列举了11个关于字符串的函数公式。一、EXACT(两个字符串进行结果比较)比较两个字符串是否完全相同(这里是要区分...
- 详细介绍一下Python中如何对字符串进行操作?
-
在Python中,字符串做为一种常见的数据处理类型,几乎在每个应用程序中都会被用到。而作为Python中使用最广泛的数据类型Python也是提供了很多强大的方法来支持对于字符串的处理操作。下面我们就来...
- Java中你知道几种从字符串中找指定的字符的数量
-
遇到这样的问题,常规的思路估计就是遍历String,然后逐个对比。下面先看循环遍历循环遍历privatestaticintgetNum(StringoriginStr,Stringtarg...
- C语言strcspn函数详解:字符串的“扫雷探测器”
-
strcspn是C语言标准库中的一个函数,定义在头文件中。它用于计算从字符串的开始到首次出现任何属于指定字符集合的字符之间的字符数量。换句话说,strcspn计算的是主字符串中不包含指定字符集...
- 如何使用 Python 的 f-string 进行字符串格式化
-
Python中的字符串格式化曾经有点麻烦。必须在...
- java判断字符串中是否包含某个字符
-
1使用String类的contains()方法contains()方法用于判断字符串中是否包含指定的字符或字符串。语法如下:publicbooleancontains(CharSequence...
- Python基础:f-string不同数据类型的格式化选项,终极指南!
-
上一篇文章我们介绍了4种字符串格式化方法,其中最现代、最直观的方式是f-string,从Python3.6开始引入,而且时不时就增加一些超级优雅的小改进。今天,钢铁老豆想要继续给大家展开介绍不同数据...
- Excel查找指定字符串,返回相应的结果
-
通过下面的函数,可以实现查找指定字符串,若找到返回“有”,若找不到返回“无”。=IF(ISNUMBER(SEARCH("失业",G3)),"有","无")...
- 一个list中,有b.a.b.c.b.b.写个方法去掉所有b
-
importjava.util.ArrayList;importjava.util.List;publicclassRemoveBFromStringList{/**...
- 掌握Python f-string(掌握催眠能力之后的日常生活)
-
f-string,通常称为格式化字符串文本,是Python3.6中添加的一项强大功能,它提供了一种将表达式包含在字符串文本中的清晰实用的方法。,...
- 深入了解字符串:定义、转义字符和字符串下标
-
字符串是编程中常见的数据类型之一,用于表示文本信息。在绝大多数编程语言中,字符串都是由一系列字符组成的序列,可以包含字母、数字、符号以及空格等。字符串的定义:...
- 100个Java工具类之70:字符串处理工具类StringUtils
-
StringUtils是常用的工具类,提供大量处理字符串的静态方法。StringUtils主要特点...
- Shell中针对字符串的切片,截取,替换,删除,大小写操作
-
切片返回字符串变量var的长度...
- Sqlite - 常规函数 - RTRIM(sqlite命令行工具)
-
在SQLite中,RTRIM函数是一个用于处理字符串的函数,其主要作用是移除字符串右侧(尾部)的指定字符。如果不指定要移除的字符,默认会移除字符串右侧的空格字符。以下是对RTRIM函数的详细...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)