本文摘要了《Java多线程设计模式》一书中提及的 Immutable 模式的适用场景,并针对书中例子(若干名称有微调)给出一份 C++ 参考实现及其 UML 逻辑图,也列出与之相关的模式。
◆ 适用场景
多个线程在同时访问共享数据时,只需要读取数据而不必修改数据。
◆ 解决方案
无需使用锁机制,也不提供修改共享数据的应用程序接口(API)。
◆ 参考实现
例子模拟 3 个打印机不停地打印人的信息。
class Person
{...stringget_name(){...}stringget_address(){...}friendstd::ostream &operator<<(std::ostream & os, Person const& person){...}};
Person 是一个 Immutable 类,没有使用锁机制,也不提供修改其中内容的接口。
class Printer
{...Person const&__person__;...voidrun() #1{while (true) #2cout << __name__ << "(" << std::this_thread::get_id() << ") prints " << __person__ << endl;}};...int
main(int argc, char * argv[])
{...Person alice("Alice", "Alaska");Printer p1("Printer1", alice);Printer p2("Printer2", alice);Printer p3("Printer3", alice);thread t1(&Printer::run, &p1);thread t2(&Printer::run, &p2); #3thread t3(&Printer::run, &p3);t1.join();t2.join(); #4t3.join();...
}
Printer::run() 作为线程的初始函数(#1),模拟打印机不停地打印人的信息(#2)。在主线程中启动这 3 个打印机子线程(#3)后,等待子线程完成(#4)。
以下类图展现了代码主要逻辑结构,
以下顺序图展现了线程间的并发中的交互。
◆ 验证测试
笔者在实验环境一中编译代码(-std=c++11)成功后运行可执行文件,
$ g++ -std=c++11 -lpthread immutable.cpp
$ ./a.out
运行结果如下:
Printer1(1992647760) prints [ Person: name = Alice, address = Alaska ]
Printer3(1975862352) prints [ Person: name = Alice, address = Alaska ]
Printer2(1984255056) prints [ Person: name = Alice, address = Alaska ]
Printer2(1984255056) prints [ Person: name = Alice, address = Alaska ]
Printer2(1984255056) prints [ Person: name = Alice, address = Alaska ]
Printer3(1975862352) prints [ Person: name = Alice, address = Alaska ]
Printer1(1992647760) prints [ Person: name = Alice, address = Alaska ]
Printer2(1984255056) prints [ Person: name = Alice, address = Alaska ]
...
◆ 相关模式
- 对多个线程进行共享互斥,可以使用 Single Threaded Execution 模式。
- 想要分离“读”线程和“读”线程,可以使用 Read-Write Lock 模式。
◆ 最后
完整的代码请参考 [gitee] cnblogs/18752329 。
致《Java多线程设计模式》的作者结城浩。写作中也参考了《C++并发编程实战》中的若干建议,致作者 Anthony Williams 和译者周全等。