多线程程序设计(一)——Single Threaded Execution
本文摘要了《Java多线程设计模式》一书中提及的 Single Threaded Execution 的适用场景,并针对书中例子(若干名称有微调)给出一份 C++ 参考实现及其 UML 逻辑图,也列出与之相关的模式。
◆ 适用场景
避免因多个线程同时访问一个共享数据而破坏数据的完整性。
◆ 解决方案
使用互斥元与 RAII(资源获取即初始化)相配合,保护临界区,保证同一时间点内仅有一条线程能访问共享数据。
◆ 参考实现
例子模拟 3 个人频繁地经过一扇只能允许一个人经过的门。当人通过门的时候,程序会打印出已经通过的人次数和当前人的信息。
class Gate
{
...
mutable
mutex #2
__mtx__;
void
__check__()
{
if (__name__[0] != __address__[0])
std::printf("%s\n", ("***** BROKEN *****" + to_string()).c_str());
else
std::printf("%s\n", ("******* OK *******" + to_string()).c_str());
}
....
void
pass(string name, string address) #1
{
lock_guard<mutex> guard(__mtx__); #3
...
__check__(); #4
}
string
to_string() const
{
...
}
};
一个人只能独自通过这扇门,这个过程被定义为临界区(#1),该区域由互斥元 __mtx__(#2)来保护。为简化在正常和异常情况下互斥元的上锁和开锁操作,用实现了 RAII 语法的 lock_guard 类模板来包覆(#3)。通过门的过程中,打印当前人员通过的信息(#4)。
class User
{
...
Gate &
__gate__;
...
void
run() #1
{
std::printf("%s\n", (__name__ + " BEGIN").c_str());
while (true) { #2
__gate__.pass(__name__, __address__);
std::this_thread::sleep_for(milliseconds(std::rand() % 1000));
}
}
};
...
int
main(int argc, char * argv[])
{
...
Gate gate;
User alice("Alice", "Alaska", gate);
User bobby("Bobby", "Brazil", gate);
User chris("Chris", "Canada", gate);
thread t1(&User::run, &alice);
thread t2(&User::run, &bobby); #3
thread t3(&User::run, &chris);
t1.join();
t2.join(); #4
t3.join();
...
}
User::run() 作为线程的初始函数(#1),模拟人频繁地通过门(#2)。在主线程中启动这 3 个人的子线程(#3)后,等待子线程完成(#4)。
以下类图展现了代码主要逻辑结构,
以下顺序图展现了线程间并发中的交互。
◆ 验证测试
笔者在实验环境一中编译代码(-std=c++11)成功后运行可执行文件,
$ g++ -std=c++11 -lpthread single_threaded_execution.cpp
$ ./a.out
运行结果如下:
Alice BEGIN
Bobby BEGIN
Chris BEGIN
***** OK ***** No.1: Bobby, Brazil
***** OK ***** No.2: Alice, Alaska
***** OK ***** No.3: Chris, Canada
***** OK ***** No.4: Bobby, Brazil
***** OK ***** No.5: Chris, Canada
***** OK ***** No.6: Chris, Canada
***** OK ***** No.7: Alice, Alaska
***** OK ***** No.8: Bobby, Brazil
***** OK ***** No.9: Chris, Canada
***** OK ***** No.10: Bobby, Brazil
***** OK ***** No.11: Alice, Alaska
***** OK ***** No.12: Bobby, Brazil
***** OK ***** No.13: Chris, Canada
***** OK ***** No.14: Bobby, Brazil
***** OK ***** No.15: Alice, Alaska
***** OK ***** No.16: Alice, Alaska
...
可以看到三个线程交替地、顺序地打印出已经通过的次数和当前线程信息。
◆ 相关模式
- 待访问的共享数据不会改变时,可使用 Immutable 模式。
- 想要分离“读”线程和“读”线程,可以使用 Read-Write Lock 模式。
◆ 最后
完整的代码请参考 [gitee] cnblogs/18743090 。
致《Java多线程设计模式》的作者结城浩。写作中也参考了《C++并发编程实战》中的若干建议,致作者 Anthony Williams 和译者周全等。
受限于作者的水平,读者如发现有任何错误或有疑问之处,请追加评论或发邮件联系 green-pi@qq.com。作者将在收到意见后的第一时间里予以回复。 本文来自博客园,作者:green-cnblogs,转载请注明原文链接:https://www.cnblogs.com/green-cnblogs/p/18743090 谢谢!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器