多线程问题(续)
线程可以独立运行,但是同时又和同进程的其他线程共享资源,这就造成在需要获取共同资源的时候需要竞争对于资源的使用,所有的关于线程的使用都是在设计如何竞争环境下使用共同的资源,以及更高效的问题
线程之间共享数据
- 互斥量
std::mutex
,对于mutex的变量有lock和unlock来控制。此外,还有lock_guard来在构造锁定 析构是解锁。
std::list some_list;
std::mutex some_mutex;
void add_to_list(int new_value)
{
std::lock_guard guard(some_mutex);
some_list.push_back(new_value);
}
bool list_contains(int value_to_find)
{
std::lock_guard guard(some_mutex);
return std::find(some_list.begin(),some_list.end(),value_to_find)
!= some_list.end();
}
main
int main()
{
add_to_list(4);
std::cout<<"contains(1)="<
这是一个简略的示例,但是在实际情况下,指针和引用指向的数据需要仔细的设计好。
死锁避免的一些规则
避免嵌套锁
持有锁时,避免调用未知代码
获取锁时,按照固定的顺序,不要随意调整
锁的层次 thread_local的使用
多线程异步计算: condition_variable future promise async
condition_variable
bool more_data_to_prepare()
{
return false;
}
struct data_chunk
{
};
data_chunk prepare_data()
{
return data_chunk();
}
void process(data_chunk&)
{
}
bool is_last_chunk(data_chunk&)
{
return true;
}
std::mutex mut;
std::queue data_queue;
std::condition_variable data_cond;
void data_preparation_thread()
{
while(more_data_to_prepare())
{
data_chunk const data = prepare_data();
std::lock_guard lk(mut);
data_queue.push(data);
data_cond.notify_one();
}
}
void data_processing_thread()
{
while(true)
{
std::unique_lock lk(mut);
data_cond.wait(lk,[] {
return !data_queue.empty();
}); // 条件等待
data_chunk data = data_queue.front();
data_queue.pop();
lk.unlock();
process(data);
if(is_last_chunk(data))
break;
}
}
在两个线程中分别执行
int main()
{
std::thread t1(data_preparation_thread);
std::thread t2(data_processing_thread);
t1.join();
t2.join();
}
future & promise
int fun1()
{
cout<< "find the anser"< answer = std::async(fun1);
fun2();
std::cout<
ex2
#include
#include
#include
#include
#include
#include // accumulate
using namespace std;
void accumulat( vector::iterator first,
vector::iterator last,
promise &accumulate_promise)
{
int sum = accumulate(first, last, 0);
accumulate_promise.set_value(sum); // Notify future
}
int main(int argc, char *argv[])
{
try {
vector numbers = { 1, 2, 3, 4, 5, 6 };
promise accumulate_promise;
future accumulate_future = accumulate_promise.get_future();
thread work_thread(accumulat, numbers.begin(), numbers.end(), ref(accumulate_promise));
//accumulate_future.wait();
cout << "result = " << accumulate_future.get() << '\n';
work_thread.join(); // wait for thread completion
}
catch ( exception &e)
{
cerr << e.what();
}
return 0;
}
内存模型
- 对同一段内存修改的未定义行为
- atomic原子类型的存储 memory order问题
store
load
读写顺序模型
atomic类型的操作:
除了一组通常的操作(load()、store()、exchange()、compare_exchange_weak()和compare_exchange_strong())之外,像std::atomic
std::atomic
不要在锁定范围之外,向受保护的数据通过将其作为参数传递给用户所提供的函数的方式,传递指针和引用。一般情况下,编译器无法为std::atomic
有锁和无锁的并发设计
todo
七、C++模板问题 模板元编程 POD 类型萃取
template
- 类的模板可以偏特化,函数的不可以,因为函数偏特化的功能可以通过重载来实现
- 类的特化问题,偏特化等
- 函数的模板
- 类的模板问题
ref chromium //third_party/blink/renderer/platform/heap/heap.h
// Constructs an instance of T, which is a garbage collected type. This special
// version takes size which enables constructing inline objects.
template
T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) {
T* object = MakeGarbageCollectedTrait::Call(additional_bytes,
std::forward(args)...);
PostConstructionHookTrait::Call(object);
return object;
}
多参数问题,函数模板,完美转发,特化,类型萃取,MakeGarbageCollectedTrait ,GC类型萃取
template
struct MakeGarbageCollectedTrait {
template
static T* Call(Args&&... args) {
static_assert(WTF::IsGarbageCollectedType::value,
"T needs to be a garbage collected object");
static_assert(
std::is_trivially_destructible::value ||
std::has_virtual_destructor::value || std::is_final::value ||
internal::IsGarbageCollectedContainer::value ||
internal::HasFinalizeGarbageCollectedObject::value,
"Finalized GarbageCollected class should either have a virtual "
"destructor or be marked as final");
static_assert(!IsGarbageCollectedMixin::value ||
sizeof(T) <= kLargeObjectSizeThreshold,
"GarbageCollectedMixin may not be a large object");
void* memory = T::template AllocateObject(sizeof(T));
HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
// Placement new as regular operator new() is deleted.
T* object = ::new (memory) T(std::forward(args)...);
header->MarkFullyConstructed();
return object;
}
template
static T* Call(AdditionalBytes additional_bytes, Args&&... args) {
static_assert(WTF::IsGarbageCollectedType::value,
"T needs to be a garbage collected object");
static_assert(
std::is_trivially_destructible::value ||
std::has_virtual_destructor::value || std::is_final::value ||
internal::IsGarbageCollectedContainer::value ||
internal::HasFinalizeGarbageCollectedObject::value,
"Finalized GarbageCollected class should either have a virtual "
"destructor or be marked as final.");
const size_t size = sizeof(T) + additional_bytes.value;
if (IsGarbageCollectedMixin::value) {
// Ban large mixin so we can use PageFromObject() on them.
CHECK_GE(kLargeObjectSizeThreshold, size)
<< "GarbageCollectedMixin may not be a large object";
}
void* memory = T::template AllocateObject(size);
HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
// Placement new as regular operator new() is deleted.
T* object = ::new (memory) T(std::forward(args)...);
header->MarkFullyConstructed();
return object;
}
};
POD, RTTI问题
STL部分容器、算法的实现
gcc gdb使用等等
gcc 用法简介
- 预处理
gcc -E hello.c -o hello.i or 或 gcc -E test.c - 生成汇编
** gcc -S asmex.cpp -lstdc++ -std=c++11 -o asmex3.s
** gcc -s hello.c -o hello.s or ** gcc -s hello.i -o hello.s - 生成目标文件
gcc -c hello.s -o hello.o or ** gcc -S hello.c -o hello.o - 链接目标文件
gcc hello.o -o hello
直接生成 gcc hello.cpp -lstdc++ -std=c++11 -o hello // 带参数编译 ./hello运行
gcc hello.c
多个文件 gcc hello1.c hello2.c -o hello
g++ -std=c++14 -g3 -pthread -o2 le007.cpp -o le07
静态库和动态库的问题 todo
多个文件以及大型程序的组织参见后文
gdb用法简介. lldb用法
- 启动调试
- 断点设置
- 变量查看
- 单步调试
- 源码查看
字符问题 对齐问题
todo
跨平台设计问题
跨平台 -- OS
- ifdef 宏定义
- impl设计
- 目录 命名等区分
跨平台 -- 底层芯片的设计区分
这部分大部分都是涉及到高性能的问题需要注意
- 线程安全设计时 例如volitile atomic等涉及到内存屏障的问题部分芯片支持的情况不一样(大部分主流芯片都比较一致)
- 涉及到L1(2,3)cache
- 涉及到neon优化 和GPU计算高度相关的设计需要注意不同芯片支持的情况
- 需要注意字符宽度,字符对齐 32位 64位(兼容32位)的区别
- size_t的使用以及由来 数据总线宽度 和地址宽度的问题
七、 编译 链接过程 以及大型程序的组织 server ex
todo
设计模式
设计模式六大原则
总原则:开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。
1、单一职责原则
不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不然,就应该把类拆分。
2、里氏替换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。
里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
历史替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
5、迪米特法则(最少知道原则)(Demeter Principle)
就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。
最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。
6、合成复用原则(Composite Reuse Principle)
原则是尽量首先使用合成/聚合的方式,而不是使用继承。
三大类 23钟设计模式
创建型模式
工厂模式 抽象工厂模式 build模式 单例模式 原型模式
工厂模式 & 抽象工厂模式
- 定义Product
class Product {
public:
Product() {}
};
class ConcreteProduct: public Product {
public:
ConcreteProduct() {}
}
- 定义工厂
class Factory {
public:
////////
Product* FactoryMethod() {
return new Product();
}
// or
Product* FactoryMethod2(char * productName) {
if (strcmp(productName, "xxxxxx")) {
return new ConcreteProduct();
// todo else if
}
private:
Product * product;
}
class ConcreteFactory : public Factory {
public:
Product * FactoryMethod () {
return new ConcreteProduct();
}
}
单例模式
danli
class Singleton {
public:
Singleton() {
cout<<"Singleton default construct"< lock(mu); // 加锁
if (_instance == NULL) {
_instance = new Singleton();
}
}
return _instance;
}
private:
static Singleton * _instance;
// 考虑线程安全
static mutex mu;
};
- 初始化static变量
Singleton * Singleton::_instance = nullptr;
mutex Singleton::mu;
call_once方式
class Singleton{
public:
static Singleton& getInstance(){
std::call_once(initInstanceFlag, &Singleton::initSingleton);
// volatile int dummy{};
return *instance;
}
private:
Singleton() = default;
~Singleton() = default;
Singleton(const MySingleton&) = delete;
Singleton& operator= (const MySingleton&) = delete;
static Singleton* instance;
static std::once_flag initInstanceFlag;
static void initSingleton() {
instance = new Singleton;
}
};
Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::initInstanceFlag;
- 实际调用示例
void print() {
//this_thread::sleep_for(std::chrono::milliseconds(1000));
Singleton::getInstance()->SingletonPrint();
}
int main() {
thread tA(print);
thread tB(print);
tA.join();
tB.join();
return 0;
}
Build模式
class Maze {
public:
Maze() { cout<<"Maze construct function<BuildRoom(10);
builder->BuildDoor(10,11);
}
private:
MazeBuilder * builder;
};
proto模式
class Proto {
public:
//virtual Proto() = delete;
virtual ~Proto() {}
virtual Proto* clone() = 0;
virtual void print() = 0;
};
class ConCreteProto : public Proto{
public:
ConCreteProto() {};
ConCreteProto(int _val, const string & _valStr) {
val = _val;
valStr = _valStr;
}
virtual ~ConCreteProto( ) {}
virtual Proto* clone() {
ConCreteProto *p = new ConCreteProto();
p->val = val;
p->valStr = valStr;
return p;
}
void print() {
cout<<"val = "<
结构型模式
Bridge Adapter 装饰 组合 享元模式 facade Proxy模式
适配器模式 Adapter
class Shape {
public:
virtual void BoundingBox() = 0;
};
class TextView {
public:
int getExtent() { return 1;}
};
// 两种不同adapter方式 --1
class TextShape:public Shape {
public:
TextShape(TextView * _view) : view(_view) {
}
void BoundingBox() {view->getExtent();}
private:
TextView * view;
};
// 两种不同adapter方式 --2
class TextShape : public Shape, private TextView {
public:
TextShape() {
}
void BoundingBox() { getExtent()}
};
桥模式 Bridge
class WindowImp {
public:
virtual void impDrawBound() = 0;
};
class Window {
public:
void drawBound() {
imp->impDrawBound();
}
private:
WindowImp * imp;
};
class XWindowImp : public WindowImp {
public:
void impDrawBound() {
cout<< "imp draw bound"<
Proxy模式
class Graphic {
public:
virtual void Draw() = 0;
virtual void GetExtend() = 0;
};
class Image : public Graphic {
public:
void Draw() {}
void GetExtend() {}
Image * loadImage() { Image * m = new Image(); return m;}
};
class ImageProxy : public Graphic {
public:
void Draw() {
if(image == nullptr) {
image = loadImage();
}
image->Draw();
}
void GetExtend() {
}
private:
Image * image;
}
Flyweight享元模式
运用共享技术有效地支持大量细粒度的对象
class Flyweight {
public:
virtual void draw() = 0;
};
class ConcreteFlyweight {
public:
void draw() {
cout<<"drawing"< flyweightMap;
};
装饰模式
动态地给一个对象添加一些额外的职责
class Component {
public:
virtual void draw() = 0;
};
class ConcreteComponent : public Component {
public:
void draw () {
cout<< "ConcreteComponent draw "<draw();
}
protected:
Component * component;
};
class XDecorate : public Decorate {
public:
XDecorate(Component * _component) : Decorate(_component) {}
//
void draw() {
Decorate::draw();
addOperation();
}
private:
void addOperation() { cout<<"addOperation"<
C++初始化列表的注意事项。
In a non-delegating constructor, initialization proceeds in the following order:
— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
— Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
— Finally, the compound-statement of the constructor body is executed.
组合
class Component {
public:
virtual void operation() = 0;
};
class Leaf : public Component {
public:
void operation () {
cout<<"Leaf operation"<operation();
}
}
void add(Component * _component) {
children.push_back(_component);
}
void remove(Component * _component) {
}
private:
vector children;
};
facade
行为模式
模板模式
class Game { // 定义基础游戏
public:
explicit Game(uint32_t players): m_no_of_players(players) {}
void run() {
start();
while (!have_winner())
take_turn();
cout << "Player " << get_winner() << " wins.\n";
}
protected:
virtual void start() = 0;
virtual bool have_winner() = 0;
virtual void take_turn() = 0;
virtual uint32_t get_winner() = 0;
uint32_t m_current_player{0};
uint32_t m_no_of_players{0};
};
class Chess : public Game { // 定义具体游戏规则
public:
explicit Chess(): Game {2} {}
protected:
void start() {
cout << "Starting chess with " << m_no_of_players << " players\n";
}
bool have_winner() { return m_turns == m_max_turns; }
void take_turn() {
cout << "Turn " << m_turns << " taken by player " << m_current_player << "\n";
m_turns++;
m_current_player = (m_current_player + 1) % m_no_of_players;
}
uint32_t get_winner() { return m_current_player; }
private:
uint32_t m_turns{0}, m_max_turns{4};
};
策略模式
策略模式 可以为client提供一系列不同的实现方式
class Compositor {
public:
void strategy() = 0;
};
class XCompositor {
public:
void strategy() {
cout<<"XCompositor strategy"
}
};
class WCompositor {
public:
void strategy(int v) { // depends on v
cout<<"WCompositor strategy"
}
};
class Composition {
public:
void SetStrategy(int strategyEnum) {
switch(strategyEnum) {
compositor = new WCompositor;
break;
}
void DoStrategy() {
compositor->strategy();
}
private:
Compositor * compositor;
}
状态模式
- Classic
class StateContext;
class State {
public:
virtual void open(StateContext * context) = 0;
virtual void send(StateContext * context) = 0;
virtual void close(StateContext * context) = 0;
protected:
void changeState(StateContext * context, State *state);
};
class StateContext {
public:
void open() {
state->open(this);
}
void send() {
state->send(this);
}
void close() {
state->close(this);
}
friend class State;
void changeState(State * _state) {
state = _state;
}
private:
State * state;
};
class XState : public State {
public:
static State * getInstance() {
return new XState();
}
void open(StateContext * context) {
cout<<"XState open"<changeState(state);
}
};
todo modern C++ design pattern
观察者模式
class Observer {
public:
virtual void update() = 0;
};
class Subject {
public:
void doSub() {}
void notify() {
for(auto observer:observers) {
observer->update();
}
}
void attach(Observer * ob) {
observers.push_back(ob);
}
private:
list observers;
};
class XObserver : public Observer {
public:
void update() {
cout<<"XObserver update"<
备忘录memento
中介模式
command
visitor
职责链
迭代
interprate
Modern Design Patterns
Type Erasure
CRTP
// CRTP example
template
class Base {
public:
void show() const {
static_cast(this)->show();
}
Base operator++() {
static_cast< T*>(this)->operator++();
}
};
class Derive : public Base {
public:
Derive() : val(0) {}
void show() const {
cout<<"derive class object val = "<val);
return *this;
}
private:
int val;
};
example
Derive d;
Base *b = &d;
b->show();
++(*b);
b->show();
Expression Templates
Policy Based Design
面向对象的内存布局 , 引用折叠
各类继承方式的内存布局情况
一般继承,virtual继承,菱形继承,等等这些情况的内存布局,以及涉及到static成员的内存布局以及常见使用示例。