关于c++:C并发与多线程-11stdatomic叙谈stdlaunchstdasync-深入

std::atomic 叙谈原子类模板齐全专用于根本整数类型(bool除外),以及 <cstdint> 中 typedef 所需的任何扩大整数类型。专用的根本数据类型: charsigned charunsigned charshortunsigned shortintunsigned intlongunsigned longlong longunsigned long longchar16_tchar32_twchar_textended integral types (if any)附加的成员函数: atomic::fetch_addatomic::fetch_subatomic::fetch_andatomic::fetch_oratomic::fetch_xoratomic::operator++atomic::operator--operator (comp. assign.)对于 bool 实例化,仅反对惯例原子操作。请留神,大多数 c-style 原子类型都是这些专门化的别名(或这些专门化继承的基类的别名)原子操作还局部专用于指针类型,具备一下附加成员函数:atomic::fetch_addatomic::fetch_subatomic::operator++atomic::operator--operator (comp. assign.)std::launch(std::async) 深刻了解std::async enum class launch : /* unspecified */ { async = /* unspecified */, deferred = /* unspecified */, /* implementation-defined */};此枚举类型用于定义 aync 异步调用中的启动策略。launch::async入口函数由新线程异步调用,并将其返回其与共享状态的拜访点同步。#include <iostream>#include <future>#include <thread>using namespace std;bool async_func () { cout << "async_func begin " << std::this_thread::get_id() << endl; cout << "async_func end" << endl; return true;}int main (){ cout << "main begin " << std::this_thread::get_id() << endl; std::future<bool> fut = std::async (launch::async, async_func); // 创立新线程并调用线程入口函数 cout << fut.get() << endl; cout << "main end" << endl; return 0;}输入: ...

February 14, 2021 · 1 min · jiezi

关于c++:LX-COG-12864R1-LCD-Sample-Code

IntroductionSample code for driving LX COG 12864R1 LCD. NOTE For arudino only.But it's very easy to apply on STM.To run the code, you'd better to have a Arduino Mega 2560 which can print the log.Code// The .ino file.// Define PINs#define CS 2#define RST 3#define DC 4#define SCL 21#define SDA 20#define setPin(pin, x) digitalWrite(pin, (x) ? HIGH : LOW)#define cs(x) setPin(CS, (x))#define reset(x) setPin(RST, (x))#define dc(x) setPin(DC, (x))#define scl(x) setPin(SCL, (x))#define sda(x) setPin(SDA, (x))void log(const char* str) { Serial.println(str);}void spi_delay(uint16_t x) { while(x > 0) { x--; }}void spi_send(uint8_t val) { for(int i = 0; i < 8; i++) { if (val & 0x80) { sda(1); } else { sda(0); } spi_delay(1); scl(1); scl(0); val <<= 1; }}void lcd_cmd(uint8_t val) { cs(0); dc(0); spi_send(val); cs(1); dc(1);}void lcd_data(uint8_t val) { cs(0); dc(1); spi_send(val); cs(1); dc(1);}void lcd_init() { log("Reset 1"); reset(1); delay(1000); log("Reset 2"); reset(0); delay(1000); log("Reset 3"); reset(1); delay(1000); log("Reset internal"); lcd_cmd(0xe2); // Internal reset lcd_cmd(0xe3); // reset signal // delay(3000); log("Display off"); lcd_cmd(0xae); // display off // delay(3000); log("ADC select"); lcd_cmd(0xa0); // ADC select lcd_cmd(0xc8); // command output select lcd_cmd(0x2f); // power control // delay(3000); // SET dir // log("Set direction"); // log("Reversed"); lcd_cmd(0xa1); //0b10100001); // Reverse // log("Normal"); lcd_cmd(0xa0); // 0b10100000); // Normal // delay(3000); log("Inverse display"); // Inverse display // log("Reversed"); lcd_cmd(0xa7); // 0b10100111); // Reverse // log("No"); lcd_cmd(0xa6); // 0b10100110); // Normal // delay(3000); log("All pixels on"); // // All pixels on // lcd_cmd(0xa5); // 0b10100101); // All on // lcd_cmd(0xa4); // 0b10100100); // Normal // delay(3000); log("Set bias"); // bias log("1/9 bias"); lcd_cmd(0xa2); //(0xa2 1/9 bias,1/65 duty ) // log("1/7 bias"); lcd_cmd(0xa3); // 1/7 // delay(3000); // log("Page blink"); // // Page Blink Page // lcd_cmd(0xd5); // lcd_cmd(0x0); // Blink all page: 0xF // delay(3000); // Ratio is a key parameter which haverily affects the invisibility. log("Select resistor ratio"); // select resistor ratio Rb/Ra: 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 lcd_cmd(0x22); // delay(3000); log("Select volume"); lcd_cmd(0x81); // select volume // delay(3000); log("vop"); lcd_cmd(0x29); // 0x15); //0x29); // vop // delay(3000); lcd_cmd(0xf8); // x4 lcd_cmd(0x08); // x4 // delay(3000); log("Initial page"); lcd_cmd(0xb0);//set page address lcd_cmd(0x10);//set column address lcd_cmd(0x00); for(int col=0; col < 128; col++) { lcd_data(0x00); // lcd_data(0b11110000); } // delay(3000); log("Display on"); lcd_cmd(0xaf); //display on // delay(3000);}uint8_t img[] = { 0xFF,0x01,0x01,0x01,0x01,0x01,0x09,0x09,0xFD,0xFD,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xA0,0xA0,0xBF,0xBF,0xA0,0xA0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xFF};void lcd_display() { uint8_t* ptr = img; for(int row = 0xb0; row < 0xb8; row++) { lcd_cmd(row); lcd_cmd(0x10); lcd_cmd(0x00); for(int col = 0; col < 128; col++) { lcd_data(*ptr++); } } delay(2000);}void lcd_clean(uint8_t color = 0x00) { for(int row = 0xb0; row < 0xb8; row++) { lcd_cmd(row); lcd_cmd(0x10); lcd_cmd(0x00); for(int col = 0; col < 128; col++) { // lcd_data(0x81); // lcd_data(0x81); lcd_data(color); } } // delay(1000);}void setup() { // put your setup code here, to run once: pinMode(CS, OUTPUT); pinMode(RST, OUTPUT); pinMode(DC, OUTPUT); pinMode(SCL, OUTPUT); pinMode(SDA, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600);}void loop() { // put your main code here, to run repeatedly: lcd_init(); uint8_t color = 0x00; while(1) { // delay(1500); digitalWrite(LED_BUILTIN, HIGH); log("Clean"); lcd_clean(color++); // if (color == 0xFE) color = 0x00; log("Display"); lcd_display(); // reset(0); delay(100); // lcd_display(); digitalWrite(LED_BUILTIN, LOW); // reset(1); delay(100); }}Good Luck!

February 12, 2021 · 3 min · jiezi

关于c++:Need-For-Speed-Nodejs-Module-In-C

IntroductionThe reason can't be more simple: the need for speed. According to a simple test between node-uuid and C++ uuid, the truth was told: C++ is faster. The time consumptions of 1M generations of uuid is almost 3s(node-uuid) vs. 0.3s(C++ modules based on boost uuid). So, the advices is: crucial module should be written in C++, if you have time for this. node-uuid Module in C++node-uuid.h#ifndef NODE_UUID_H#define NODE_UUID_Husing namespace v8;#define NODE_UUID_CLS_NAME "nodeUuid"namespace igame{ namespace uuid { void initialize(Handle<Object> exports); }} // ns#endifnode-uuid.cpp#include "node_uuid.hpp"// #include <boost/lexical_cast.hpp>namespace igame{ namespace uuid { Persistent<Function> constructor; buid::random_generator uuid_generator; uint32_t uuid_count; Handle<Value> generate_uuid(const Arguments& args); Handle<Value> get_count(Local<String> property, const AccessorInfo& info); void initialize(Handle<Object> exports) { exports->Set(String::NewSymbol("next"), FunctionTemplate::New(generate_uuid)->GetFunction()); exports->SetAccessor(String::NewSymbol("count"), get_count, NULL); } Handle<Value> generate_uuid(const Arguments& args) { HandleScope scope; buid::uuid uid = uuid_generator(); uuid_count++; return scope.Close(String::New(buid::to_string(uid).c_str())); } Handle<Value> get_count(Local<String> property, const AccessorInfo& info) { HandleScope scope; return scope.Close(Integer::New(uuid_count)); } } // ns} // nsTesttest.js ...

February 12, 2021 · 1 min · jiezi

关于c++:C-Style-IO-Access-For-STM32

IntroductionFor STM, the common ways to manipulate low hardware are HAL and memory/register access. For third-party hardwares, there are no HAL support and we have to do memory/register access. For example, for ili9341 TFT LCD, the driving code looks like the following: // Define the memory model for IO/Register access.typedef struct { __IO uint16_t reg; __IO uint16_t mem;} LCD_TypeDef;#define LCD_BASE ((uint32_t)(0x6C000000 | 0x000007FE))#define LCD ((LCD_TypeDef *)LCD_BASE)// Write commands by assignment.// NOTE: If people know some about FPGA will// figure out that they are much similar.INLINE void lcd_cmd(uint16_t cmd) { LCD->reg = cmd;}// Write data by assignment.INLINE void lcd_data(uint16_t dat) { LCD->mem = dat;}INLINE void lcd_cmd_data(uint16_t cmd, uint16_t data) { LCD->reg = cmd; LCD->mem = data;}Personally, I prefer to C++. So the C++ style code will be: ...

February 12, 2021 · 2 min · jiezi

关于c++:Acwing算法基础课-二数据结构

数据结构链表与邻链表struct Node{ int val; Node *next}new Node(); //十分慢数组模仿单链表 动态链表int head; //头节点int e[N]; //值int ne[N]; //next指针int idx; //数组用到第几个点// 初始化void init(){ head = -1; idx = 0;}// 在链表头插入一个数avoid insert_head(int a){ e[idx] = a; ne[idx] = head; head = idx; idx++ ;}// 将头结点删除,须要保障头结点存在void remove(){ head = ne[head];}// 将a插入到第k个点前面void add(int k, int a){ e[idx] = a; ne[idx] = ne[k]; ne[k] = idx; idx ++;}//将下标是k的后边的点删掉void remove(int k){ ne[k] = ne[ne[k]];}数组模仿双链表(优化某些问题)每一个点有两个指针 int e[N];int l[N];int r[N];//初始化void init(){ // 0示意左端点(head), 1示意右端点(tail) r[0] = 1; l[1] = 0; idx = 2;}//在下标是k的点的左边,插入xvoid add(int k, int x){ e[idx] = x; r[idx] = r[k]; //不能用 k + 1 l[idx] = k; l[r[k]] = idx; //不能用 k + 1 r[k] = idx; }//在k的右边插入xadd(l[k], x);//删除第k个点void remove(int k){ r[l[k]] = r[k]; l[r[k]] = l[k];}邻接表 存储树和图 ...

February 11, 2021 · 1 min · jiezi

关于c++:CS144-Lab-Assignments-手写TCP-LAB2

CS 144: Introduction to Computer Networking, Fall 2020https://cs144.github.io/My Repohttps://github.com/wine99/cs1... Translating between 64-bit indexes and 32-bit seqnos 留神 wrapping_integers.hh 中的这三个办法: inline int32_t operator-(WrappingInt32 a, WrappingInt32 b) { return a.raw_value() - b.raw_value(); }//! \brief The point `b` steps past `a`.inline WrappingInt32 operator+(WrappingInt32 a, uint32_t b) { return WrappingInt32{a.raw_value() + b}; }//! \brief The point `b` steps before `a`.inline WrappingInt32 operator-(WrappingInt32 a, uint32_t b) { return a + -b; }上面的两个加减,别离是在 WrappingInt32 上加上或减去一个 uint32_t,失去的后果依然是一个 WrappingInt32,其意义是别离为把 a 这个 WrappingInt32 向前或向后挪动 |b| 个单位间隔。 ...

February 10, 2021 · 3 min · jiezi

关于c++:C并发与多线程-8asyncfuturepackagedtaskpromise

std::future类模板template <class T> future;template <class R&> future<R&>; // specialization : T is a reference type (R&)template <> future<void>; // specialization : T is voidfuture 是一个对象,能够从某个提供对象或函数中检索值,如果在不同线程中,则能够正确同步此拜访。“无效” future 对象,通过调用一下函数之一来结构: asyncpromise::get_futurepackaged_task::get_futurefuture 对象仅在他们无效时才有用。默认结构的 future 对象五项(除非挪动调配一个无效的 future)。在无效的 future 上调用 future::get 会阻塞线程,直到提供程序筹备好共享状态(通过设置值或异样)。这样,两个线程能够通过一个线程同步,期待另一个线程设置值。共享状态的生存期至多要继续到与之关联的最初一个对象开释它或销毁它为止。因而,如果与 future 相关联,共享状态能够在最后取得它的对象(如果有的话)之后持续存在。future::valid()bool valid() const noexcept; 查看无效的共享状态返回 future 对象以后是否与共享状态关联。对于默认结构的 future 对象,此函数返回 false (除非将无效的 future 调配给挪动对象)。future 只能由某些提供函数(如, async, promise::get_future 或 packaged_task::get_future)应用无效的共享状态进行初始化。一旦应用 future::get 检索了共享状态的值,则调用此函数返回 false (除非挪动调配了一个新的 future).返回值如果对象与共享状态关联,则为 ture。否则为假。// future::valid#include <iostream> // std::cout#include <future> // std::async, std::future#include <utility> // std::moveint get_value() { return 10; }int main (){ std::future<int> foo,bar; foo = std::async (get_value); bar = std::move(foo); if (foo.valid()) std::cout << "foo's value: " << foo.get() << '\n'; else std::cout << "foo is not valid\n"; if (bar.valid()) std::cout << "bar's value: " << bar.get() << '\n'; else std::cout << "bar is not valid\n"; return 0;}输入: ...

February 9, 2021 · 6 min · jiezi

关于c++:C并发与多线程-8conditionvariablewaitnotifyonenotifyall

std::condition_variable条件变量是一个对象,该对象可能阻塞调用线程,直到被告诉复原。当调用其期待函数(wait,wait_for,wait_until)之一时,它应用 unique_lock (通过互斥锁)来锁定线程,该线程将放弃阻塞状态,直到被另一个同在 condition_variable 对象上调用告诉性能的线程唤醒为止。condition_variable 类型的对象始终应用 unique_lock<mutex> 期待(无关可与任何类型的可锁定类型一起应用的代替办法,可参见 condition_variable_any)。// condition_variable example#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutex, std::unique_lock#include <condition_variable> // std::condition_variablestd::mutex mtx;std::condition_variable cv;bool ready = false;void print_id (int id) { std::unique_lock<std::mutex> lck(mtx); while (!ready) cv.wait(lck); // ... std::cout << "thread " << id << '\n';}void go() { std::unique_lock<std::mutex> lck(mtx); ready = true; cv.notify_all();}int main (){ std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(print_id,i); std::cout << "10 threads ready to race...\n"; go(); // go! for (auto& th : threads) th.join(); return 0;}输入: ...

February 8, 2021 · 2 min · jiezi

关于c++:2021年秋招-双非渣硕的我是如何拿到字节跳动研发岗SP

前言最近应邀在牛客网写C++求职专栏,又把以前的秋招总结补充了很多货色,当初想想还是收回来,心愿可能帮忙更多的老手小伙伴们。 集体状况简介 楼主本硕均读于双非院校(一般二本学校)、本硕都是计算机相关业余,英语六级程度,本科期间辅修了一个水的不能再水的英语第二学位。 本科期间学过很多语言:VB、C、C++、Java、C#都有所涉猎,研究生期间则主攻Python和C++。研二上学期开始零碎学习C++,并且一直零碎看书和实际,两头解体过、迷茫过、放荡过,但从未放弃,始终置信本人,保持咬牙走上来。所幸天道酬勤,最终也是拿到了一些不错的offer 。 投递经验 笔者从2020.6.15号正式开始投递简历,到2020.8.23号截止一共投递过94家公司,其中既有提前批(2020年6月-7月),也包含正式批(2020年7月-10月)。 小倡议:如果说求职者对本身实力不自信,能够多投投一些公司,选择面放宽一些,不要死盯着那几个大厂投。 共计口试59场(最多一天做了5场口试,那天天差点逝世),54家公司给了面试机会,54家企业中有些企业是免口试的。 秋招后果:最终胜利走到了6家公司的offer环节:字节跳动研发岗SP、华为通用软件开发、百度C++研发岗、B站后端研发岗、深服气C++研发岗以及农业银行研发岗,最初签了字节跳动,也是本人心心念念的大厂之一,十分满意了~ 接下来从6个方面对秋招进行复盘和总结,心愿可能帮到大家鸭,特地是大三大四的小学弟们。 1、算法 在秋招过程中,算法是极其重要的,再次重申一遍,真的很重要!口试就不提了,算法不过关,口试根本凉凉,面试根本都要手撕代码,很多面试过程中算法题具备一票否决权,如果你可能顺利解进去,面试也不肯定过。即便面试过了,手撕代码没撕进去,面评估计也是一般般了。然而如果算法题做不进去或者说bug太多调试不通的话,面试上基本上就跪了(集体以及身边敌人经验,不肯定精确),在牛客网上也看到过很多根底很好的牛友就是因为面试过程中的算法题没解进去而间接饮恨的,心愿大家千万器重算法这一块,千万千万要器重算法。 我大略在力扣上刷了300+,HOT100都刷了,剑指offer刷了3遍,刷完这些根本够用了,本人也有留神总结题型,常见题型就是那些,所以算法题根本没怎么拉过我后腿。一般来说,次要考的就是动静布局、贪婪、二叉树、链表、数组、字符串之类的。 举荐材料:力扣1-300题(前300道题十分经典,倡议学有余力的同学都刷一刷) 力扣HOT100(跟下面有不少是反复的,刷的时候要留神总结) 啊哈!算法、大话数据结构(这两本书都是面向老手的图书,图画很多) 剑指offer(这本书不须要多做介绍,校招必备) 挑战程序设计比赛(这本书属于进阶一点的算法书籍了,作者是ACM-ICPC寰球总冠军,能够说是世界顶级程序设计高手的经验总结了,须要缓缓消化,经典题型太多) 程序员代码面试指南(左程云大神的书,我并没有看完,只是看了其中的海量数据处理局部的题目就曾经非常受用了,在某大厂三面中就考查到了其中的海量数据集解决的问题) 2、操作系统 操作系统是比拟重要的,面试三大要点之一(操作系统、计网、数据库),我是在B站上看过一些操作系统视频,同时本人缓缓看书、看博客学的。其中死锁、虚拟内存、堆栈、过程线程、内存治理、磁盘调度等都是重点,也是面试过程中问的比拟多的一些知识点。你如果可能在面试过程中讲进去一些具体的操作系统常识,而不是泛泛而谈,必定是很加分的,比方常见知识点过程线程区别,在提到线程切换比过程更快时,你如果可能很分明明确的说进去过程切换做了哪些、线程切换做了哪些以及线程为什么比过程快,毫无疑问很加分的。 举荐材料:B站哈工大操作系统:https://www.bilibili.com/vide... B站清华大学操作系统:https://www.bilibili.com/vide... B站美国麻省理工MIT 6.828操作系统神级课程:https://www.bilibili.com/vide... 古代操作系统(也是讲操作系统的一本好书,讲的很细) 深刻了解计算机系统(赫赫有名的CSAPP,被誉为“和金子一样重要的计算机根底书籍” , 很厚的一本黑皮书,须要缓缓看) 古代操作系统:原理与实现(上海交通大学陈海波传授的著述,书中次要介绍操作系统的实践与具体实现细节等,感觉不如CSAPP) 3、计算机网络 计算机网络也是重点之一,特地是HTTP以及TCP/UDP相干知识点,算是校招必备考点了,面试必问,然而难度是逐年回升的,起因可能就在于内卷水平越来越重大了吧。比如说以前对于三次握手四次挥手只问过程,当初间接让面试者画出客户端以及服务器端的各个状态码以及解释各种意外状况,比方SYN申请失落会怎么样? 倡议计网的学习先从视频动手,而后再看经典书籍,毕竟视频中的常识都是他人总结好又给你解说的,只有本人亲自琢磨、亲自动手实际得来的常识才是本人的,本人学来的才是真,通过实际方知分晓的~ 举荐材料:B站韩立刚老师的计算机网络(韩老师讲课滑稽易懂,让你在哈哈大笑中学到很多知识点:https://www.bilibili.com/vide...) 图解HTTP、图解TCP/IP(这两本书比较简单,日本人写的,把简单的知识点简单化) 网络是怎么连贯的(这本书紧紧围绕一个问题:输出一个URL,直到咱们在网页端看到申请的内容,这两头产生了什么?抽丝剥茧将这个问题逐渐细化,带你走残缺个网页拜访的过程) 计算机网络:自顶向下办法 (也是常见经典书籍之一,重点看第三章传输层TCP/UDP) 4、Linux C++跟Linux根本是离不开的,特地是后端方向跟网络通信关系很大。在理论工作里,很多成熟的我的项目都是在Linux上进行开发的。所以有必要学一些Linux以及一些网络通信编程,网络通信波及到的知识点很多,比方IO模型、线程池、多线程之类的。自己在秋招过程中被问过不少网络通信的问题,最频繁的就是select、poll、epoll的区别以及相干底层实现了。这里也举荐一些材料,都是我集体看过的。 举荐材料:鸟哥的Linux以及Linux就该这么学这两本书(个人感觉更适宜作为一本工具书来应用,当然了,如果你有短缺的工夫也能够零碎的看上一遍,对于Linux也会有更深的意识和理解了) TCP/IP网络编程(韩国人写的,书中例子很多,适宜作为入门,另外github上有很多笔记,能够边看他人的笔记边看书,加深集体了解) Linux高性能服务器编程(游双老师的书,其中前四五章讲的是计网的货色,前面讲的很好,波及内容很多,看完就大略明确服务端编程常见知识点和所须要把握的技能了) Linux多线程服务端编程:应用muduo C++网络库 (北师大陈硕大神的书,须要很多根本,倡议前期再看,我也只是看了一小半) ...

February 8, 2021 · 1 min · jiezi

关于c++:C并发与多线程-7单例设计模式callonce

懒汉式单例类#include <iostream>#include <thread>#include <mutex>using namespace std;class Singleton{public: static Singleton* getInstance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;private: Singleton() = default; static Singleton* instance; static mutex mtx;};Singleton *Singleton::instance = nullptr;mutex Singleton::mtx;Singleton* Singleton::getInstance(){ if (instance == nullptr) { lock_guard<mutex> lck(mtx); // 留神这里 !!! if (instance == nullptr) { instance = new Singleton(); } } return instance;}void thread_func(){ Singleton* p = Singleton::getInstance(); // p-> do something ...}int main(){ thread th1(thread_func); thread th2(thread_func); th1.join(); th2.join(); return 0;}饿汉式单例类#include <iostream>#include <thread>using namespace std;class Singleton{public: static Singleton* getInstance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;private: Singleton() = default; static Singleton* instance;};Singleton *Singleton::instance = new Singleton(); // 留神这里 !!!Singleton* Singleton::getInstance(){ return instance;}void thread_func(){ Singleton* p = Singleton::getInstance(); // p-> do something ...}int main(){ thread th1(thread_func); thread th2(thread_func); th1.join(); th2.join(); return 0;}懒汉式的 call_once 实现template <class Fn, class... Args> void call_once (once_flag& flag, Fn&& fn, Args&&... args);精确执行一次可调用对象 fn ,即便同时从多个线程调用。#include <iostream>#include <thread>#include <mutex>using namespace std;class Singleton{public: static Singleton* getInstance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;private: Singleton() = default; static void createInstance(); static Singleton* instance; static once_flag onceFlag;};void Singleton::createInstance(){ instance = new Singleton();}Singleton *Singleton::instance = nullptr;once_flag Singleton::onceFlag;Singleton* Singleton::getInstance(){ call_once(onceFlag, createInstance); // 留神这里 !!! return instance;}void thread_func(){ Singleton* p = Singleton::getInstance(); // p-> do something ...}int main(){ thread th1(thread_func); thread th2(thread_func); th1.join(); th2.join(); return 0;}单例类的资源清理【饿、懒同理】#include <iostream>#include <thread>#include <mutex>using namespace std;class Singleton{ struct Recycle { ~Recycle() // 留神这里 !!! { if (instance != nullptr) { delete instance; instance = nullptr; } } };public: static Singleton* getInstance(); Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete;private: Singleton() = default; ~Singleton(); static Singleton* instance; static mutex mtx;};Singleton *Singleton::instance = nullptr;mutex Singleton::mtx;Singleton* Singleton::getInstance(){ if (instance == nullptr) { lock_guard<mutex> lck(mtx); if (instance == nullptr) { instance = new Singleton(); static Recycle recycle; } } return instance;}Singleton::~Singleton() // 留神这里 !!!{ // 单例类资源清理}void thread_func(){ Singleton* p = Singleton::getInstance(); // p-> do something ...}int main(){ thread th1(thread_func); thread th2(thread_func); th1.join(); th2.join(); return 0;}

February 7, 2021 · 2 min · jiezi

关于c++:C并发与多线程-6uniquelock-类模板详解

unique_lock 取代 lock_guardstd::lock_guard 和 std::unique_lock 都能实现主动加锁与解锁性能。std::unique_lock 外部持有 mutex 的状态(locked,unlocked),因而比 lock_guard 应用更加灵便但同时更占用空间、速度更慢。// unique_lock example#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutex, std::unique_lockstd::mutex mtx; // mutex for critical sectionvoid print_block (int n, char c) { // critical section (exclusive access to std::cout signaled by lifetime of lck): std::unique_lock<std::mutex> lck (mtx); for (int i=0; i<n; ++i) { std::cout << c; } std::cout << '\n';}int main (){ std::thread th1 (print_block,50,'*'); std::thread th2 (print_block,50,'$'); th1.join(); th2.join(); return 0;}输入: ...

February 7, 2021 · 4 min · jiezi

关于c++:QFtp源码学习及目录下载

背景须要在QT5中进行FTP文件下载,并须要反对整目录下载,通过比照抉择,最初决定应用Qt4中的QFtp来实现咱们的需要。因而决定学习源码,看清构造,做到能真正解决所要面对的问题。 合成源码Qftp一共只有四个文件,次要文件是qftp.cpp,这个文件中,有太多的类,首先按类合成到各自文件中,这样利用官网的示例代码,跑起来后,能够不便的查看代码。 类阐明class QFtpCommand : 此类是对FTP命令的封装,将命令与QIODevice设施关联起来,并返回一个惟一的标识ID。class QFtpPI : 此类是对FTP协定的封装,processReply是次要函数,应答服务端响应。class QFtpDTP : 此类是数据操作封装,数据读取、解析、存储都是在此类中解决。class QFtpPrivate : 此类是QFtp的实际操作类,被组合到QFtp类中,是逻辑解决核心。class QFtp : 此类是外壳,用户间接面对。class QUrlInfo : 此为信息类,存储接管到的每一条文件数据信息。运行流程所有的客户端命令被压入到命令堆栈。一个命令运行有两个入口:一是命令被压入堆栈时,若堆栈中只有一条命令,即被运行;二是作响应服务端响应时,类型为idle或not waiting。每个命运被结构时,都会返回惟一ID,这是很重要的一点,因为命令大多关联着一本地IO设施,在清理IO时,要留神与命令对应,因为所有的操作都是异步的。 革新list响应QFtp列当前目录的原有逻辑是取一条数据就发送一条文件或目录的音讯,这样在咱们间断遍历目录时,无奈分分明是哪个目录下的数据,无奈进行正确的递归。QFtpDTP::socketReadyRead() - 批改读取目录列表时的信号发送形式 if (pi->currentCommand().startsWith(QLatin1String("LIST"))) { QVector<QUrlInfo> infos; //减少vector来存储整个目录信息 while (socket->canReadLine()) { QUrlInfo i; QByteArray line = socket->readLine(); if (parseDir(line, QLatin1String(""), &i)) { infos.push_back(i); //emit listInfo(i); //原来在循环内,读一条数据发送一个listInfo信号 } else { if (line.endsWith("No such file or directory\r\n")) err = QString::fromLatin1(line); } } emit listInfos(infos); //改为在循环外发送新增的listInfos信号 }FtpWindow::addToList(const QVector<QUrlInfo>& urlInfos) - listInfos响应批改 ...

February 6, 2021 · 2 min · jiezi

关于c++:2021寒假刷题-洛谷P1135-BFS初学

总结: queue队列的应用memeset函数的应用BFS: 广度优先搜寻(breadth-fifirst searching,bfs),尽量广阔地搜寻,在每一步优先拜访间隔最近的结点。因为BFS须要依照 接触到的程序 来拜访,所以须要一种先入先出的数据结构——队列来辅助实现。当咱们搜寻一个结点时,将它所有的分支推入队列;解决完以后结点后,再从队列头取出下一个结点持续进行搜寻。#include<bits/stdc++.h>using namespace std;/*思路: 5 1 5 楼层:1 2 3 4 5 按钮:3 3 1 2 5 将楼层A压入队列中,而后找非法的上下楼 压入队列 一直出队 入队 直到B出队就找到了 */const int MAXN = 205;int flr[MAXN]; //存储按钮 int dis[MAXN];//寄存按按钮次数int main(){ int n,a,b; cin>>n>>a>>b; for(int i = 1;i<=n;i++){ cin>>flr[i]; } memset(dis,-1,sizeof(dis)); //memset函数初始化只能是: 0,-1 ,0x3f dis[a]= 0; queue<int> q;//创立队列, int类型 q.push(a); //把a压入队列 while(!q.empty()){ //判断是否非空 int x = q.front(); //取第一个值,front 只是返回这个值,并没有把这个值入列 q.pop(); //出列 if(x == b){ cout<<dis[x]<<endl; return 0; //这里没有写break;输出后果之后间接完结了,间接return 0即可 } int y; //下一步达到的楼层 y = x-flr[x]; if(y>0 && dis[y]==-1){ //要判断这个楼层之前没有拜访过,不然会反复拜访 dis[y] = dis[x]+1; //达到y层须要的按键次数 q.push(y); //达到了之后要把y入队 持续下一轮的判断 } y = x+flr[x]; if(y<=n && dis[y]==-1){ dis[y] = dis[x]+1; q.push(y); } } cout<<-1<<endl;}

February 5, 2021 · 1 min · jiezi

关于c++:More-Effective-C总结笔记二异常

异样条款9:利用destructors防止泄露资源只有保持这个规定,把资源封装在对象内(相似智能指针shared_ptr),通常便能够在exceptions呈现时防止泄露资源。简略来说就是,当有资源可能在函数抛异样时而无奈开释,这时能够将资源封装到对象内(RAII),利用对象的析构函数来主动开释资源,这样即便有exceptions产生,也不会有资源泄露。条款10:在constructors内阻止资源泄露(resource leak)C++只会析构已结构实现的对象。对象只有在其constructor执行结束才算是实现结构得当。因为C++不主动清理那些“结构期间抛出exceptions”的对象,所以你必须设计你的constructors,使它们在那种状况下亦能自我清理。通常这只须要将所有可能的exceptions捕获起来,执行某种清理工作,而后从新抛出exception,使它持续流传进来即可。然而,更优雅的做法实际上是将这些须要在constructor内初始化的对象视为资源,将它们交由智能指针来治理。论断是:如果你以auto_ptr(C++11后应用shared_ptr或者unique_ptr)对象来取代pointer class members,你便对你的constructors做了强化工事,罢黜了“exceptions呈现时产生资源泄露”的危机,不再须要在destructors内亲自动手开释资源,并容许const member pointers得以和non-const member pointers有着一样优雅的解决形式。条款11:禁止异样(exceptions)流出destructors之外Session::Session(){ try { logDestruction(this); } catch (...) { }}这里的catch语句块看起来什么都没做,然而表面容易骗人。这个语句块阻止了“logDestruction所抛出的exceptions”传出Session destructor之外。有两个好理由反对咱们“全力阻止exceptions传出destructors之外”。第一,它能够防止terminate函数在exception流传过程的栈开展(stack-unwinding)机制中被调用;第二,它能够帮助确保destructors实现其应该实现的所有事件。条款12:理解“抛出一个exception”与“传递一个参数”或“调用一个虚函数”之间的差别“抛出exception”与“传递参数”的相同点是:它们的传递形式有3中:by value(传值),by reference(传援用),by pointer(传指针)。然而视你所传递的是参数或exceptions,产生的事件可能齐全不同。起因是当你调用一个函数,控制权最终会回到调用端(除非函数失败以至于无奈返回),然而当你抛出一个exception,控制权不会再回到抛出端。“抛出exception”与“传递参数”的区别一:C++特地申明,一个对象被抛出作为exception时,总是会产生复制(copy)。即便catch语句参数时by reference,或者抛出对象申明为static也一样会产生复制。且复制动作永远是以对象的动态类型为本。“exception objects必定会造成复制行为”这一事实也解释了“传递参数”和“抛出exception”之间的另一个不同:后者经常比前者慢。一般而言,你必须应用一下语句:throw;能力从新抛出以后的exception,其间没有机会让你扭转被流传的exception的类型。此外,它也比拟有效率,因为不须要产生新的exception object。 “抛出exception”与“传递参数”的区别二:函数调用过程中将一个长期对象传递给一个non-const reference参数时不容许的,但对exception则属非法。“抛出exception”与“传递参数”的区别三:一般而言,调用函数传递参数过程中容许的隐式转换在“exceptions与catch子句相匹配”的过程中使不会产生的。“exceptions与catch子句相匹配”的过程中,仅有两种转换能够产生。第一种是“继承架构中的类转换”。第二种是从一个“有型指针”转为“无型指针”(所以一个参数为const void*的catch子句,可捕获任何指针类型的exception)。“抛出exception”与“传递参数”的区别四:catch子句总是依呈现程序做匹配尝试。与虚函数调用比拟,虚函数采纳”best fit“(最佳吻合)策略,而exception解决机制采纳”first fit“(最先吻合)策略。因而,相对不要将”针对base class而设计的catch子句“放在”针对derived class而设计的catch子句“之前。条款13:以by reference形式捕获exceptions相比于by reference形式,以by value形式捕捉exception,会使被传递的对象产生两次复制,产生两个正本。其中一个结构动作用于“任何exceptions都会产生的长期对象”身上,另一个结构动作用于“将长期对象复制到catch的参数上”。千万不要抛出一个指向部分对象的指针,因为该部分对象会在exception传离其scope时被销毁,因而catch子句会取得一个指向“已被销毁的对象”的指针。如果catch by reference,你就能够避开对象删除问题(by pointer会面对的)——它会让你动辄得咎,做也不是,不做也不是;你也能够避开exception objects的切割问题(派生类对象的exception objects被捕获并被视为基类对象的exception objects,将失去其派生成分。对象切割问题是因为动态编联导致的,应用援用和指针时不会产生);你能够保留捕获C++规范exceptions的能力;你也束缚了exception objects需被复制的次数。条款14:理智使用exception specificationsexception specification示例,一个只抛出int类型exceptions的函数申明为:void fun() throw(int);如果函数抛出一个并未列入exception specification的exception,这个谬误会在运行期间被测验进去,于是非凡函数unexpected会被主动调用。unexpected的默认行为是调用terminate。想要防止这种unexpected的办法就是: 不应该将templates和exception specifications混合应用。如果A函数内调用了B函数,而B函数无exception specifications,那么A函数自身也不要设定exception specifications。解决“零碎”可能抛出的exceptions(如bad_alloc)。C++容许你以不同类型的exceptions取代非预期的exceptions。如果非预期函数的替代者从新抛出以后的exception,该exception会被规范类型bad_exception取而代之。void convertUnexpected(){ throw;}set_unexpected(convertUnexpected);如果你做了上述安顿,并且每一个exception specifications都含有bad_exception,或者其基类,你就再也不用放心程序会于是非预期的exception时中止执行。理解异样解决(exception handling)的老本为了让exception的相干老本最小化,只有可能不反对exceptions,编译器便不反对;请将你对try语句块和exception specifications的应用限度于非用不可的地点,并且在真正异样的状况下才抛出exceptions。

February 5, 2021 · 1 min · jiezi

关于c++:洛谷P1451-DFS初学

大抵思路: DFS介绍: 深度优先搜寻(depth-first searching,dfs)优先向深处搜寻,直到无奈找到新的分支时再回溯。因为须要重复地后退、回溯,适宜应用递归来实现。具体地,能够在函数中枚举所有的分支,而后顺次进行递归调用。 #include<bits/stdc++.h> using namespace std; char cell[105][105]; int n,m; void dfs(int i,int j){  cell[i][j]='0';  int dx[4]={1,-1,0,0};  int dy[4]={0,0,1,-1};  for(int k = 0;k < 4;k++){  int xx = i + dx[k],yy = j + dy[k];  if(xx>=0&&xx<n&&yy>=0&&yy<m&&cell[xx][yy]!='0'){  dfs(xx,yy);  }  }  }  int main(){  cin>>n>>m; /* for(int i = 0;i < n;i++)  for(int j = 0;j < m;j++) cin>>cell[i][j]; 开始写的时候没有看输出格局,它是一串一串的,所以不能一个个输出,并且该用char数组而不是int  */   for(int i = 0;i < n;i++)  cin>>cell[i];   int ans = 0;  for(int i = 0;i < n;i++)  for(int j = 0;j < m;j++){  if(cell[i][j] != '0'){  ans++;  dfs(i,j);   }  }  cout<<ans<<endl;  }

February 5, 2021 · 1 min · jiezi

关于c++:一文说清-OCLint-源码解析及工作流分析

指标读者一线工程师,架构师 预计浏览工夫15-20min ???? 实现浏览的播种理解动态代码审核技术的原理理解动态代码审核技术工作流不得不提的 Clang因为 OCLint 是一个基于 Clang tool 的动态代码剖析工具,所以不得不提一下 Clang。Clang 作为 LLVM 的子项目, 是一个用来编译 c,c++,以及 oc 的编译器。 OCLint 自身是基于 Clang tool 的,换句话说相当于做了一层封装。它的外围能力是对 Clang AST 进行剖析,最初输入违反规定的代码信息,并且导出指定格局的报告。 接下来就让咱们看看作为输出信息的 Clang AST 是什么样子的。 Clang ASTClang AST 是在编译器编译时的一个两头产物,从词法剖析,语法分析(生成 AST),到语义剖析,生成中间代码。 形象语法树示例这里先对形象语法树有一个初步的印象。 //Example.c#include <stdio.h>int global;void myPrint(int param) { if (param == 1) printf("param is 1"); for (int i = 0 ; i < 10 ; i++ ) { global += i; }}int main(int argc, char *argv[]) { int param = 1; myPrint(param); return 0;} ...

February 3, 2021 · 6 min · jiezi

关于c++:C并发与多线程-5互斥量概念用法死锁演示及详解

互斥量的基本概念临界资源:每次只容许一个线程进行拜访(读/写)的资源线程间的互斥(竞争):多个线程在同一时刻都须要拜访临界资源mutex 类(互斥量)是一把线程锁,保障线程间的互斥 利用线程锁可能保障临界资源的平安互斥量的用法lockmutex.lock() 当锁闲暇时,获取并继续执行当锁被获取时,阻塞并期待锁开释mutex.unlock() 开释锁(同一把锁的获取和开释必须在同一线程中成对呈现)如果 mutex 在调用 unlock() 时处于闲暇状态,那么程序的行为是未定义的 lock_guard在 lock_guard 对象结构时,传入的 mutex 对象(即它治理的 mutex 对象)会被以后线程锁住。在 lock_guard 对象被析构时,它所治理的 mutex 对象会主动解锁,不再须要手动调用 lock 和 unlock 对mutex 进行上锁和解锁操作;lock_guard 对象并不负责 mutex 对象的生命周期,只是简化了上锁和解锁操作;这种采纳“资源分配时初始化”(RAII)办法来加锁、解锁,防止了在临界区中因为抛出异样或return等操作导致没有解锁就退出的问题。这极大的简化了编写mutex相干的异样解决代码。#include <iostream>#include <thread>#include <queue>#include <mutex>using namespace std;class Handle {public: void inMsgRevQueue() { for (int i=0; i<100000; ++i) { m_mutex.lock(); // 留神这里 !!! cout << "inMsgRevQueue() : " << i << endl; m_queue.push(i); m_mutex.unlock(); // 留神这里 !!! } } void outMsgRevQueue() { for (int i=0; i<100000; ++i) { lock_guard<mutex> lck(m_mutex); // 留神这里 !!! if (!m_queue.empty()) { cout << "outMsgRevQueue() : " << m_queue.front() << endl; m_queue.pop(); } } }private: queue<int> m_queue; mutex m_mutex;};int main(){ cout << "main begin" << endl; Handle handler; thread th1(&Handle::inMsgRevQueue, std::ref(handler)); thread th2(&Handle::outMsgRevQueue, std::ref(handler)); th1.join(); th2.join(); cout << "main end" << endl; return 0;}输入: ...

February 2, 2021 · 3 min · jiezi

关于c++:QT5编译使用QFtp

背景应用 QNetworkAccessManager 能够实现 Ftp 的上传/下载性能,但它没有提供例如list、cd、remove、mkdir、rmdir、rename 等性能。这种状况下,咱们能够应用QFtp,须要下载源码、编译并解决一些坑。 下载从 GitHub 下载 QFtp: https://github.com/qt/qtftp编译批改 qftp/qftp.pro,删除最初一行,module_qtftp_tests。不然编译会有谬误,这个是测试子项目,临时去除,先编译应用。批改 qftp/src/qftp/qftp.h 第47行 #include <QtFtp/qurlinfo.h> => #include <qurlinfo.h>批改 qftp/src/qftp/qftp.pro 第4,5行的+,-号调换,生成*.dll批改第4行为 CONFIG += staticlib,生成.lib和.prl用qtcreator关上qftp/qftp.pro,编译生成库文件。 放入QT5装置目录中我以Qt5.5.1为例阐明,其它版本相似 将 Qt5Ftpd.lib、Qt5Ftp.lib、Qt5Ftpd.prl、Qt5Ftp.prl 拷贝至 D:\Qt\Qt5.5.1\5.5\msvc2010\lib。将Qt5Ftpd.dll、Qt5Ftp.dll 拷贝至D:\Qt\Qt5.5.1\5.5\msvc2010\bin。将qftp.h、qurlinfo.h 拷贝至 D:\Qt\Qt5.5.1\5.5\msvc2010\include\QtNetwork,并新建一个名为 QFtp 的文件(没有后缀名),而后用本写入 #include "qftp.h"。运行示例我的项目作为qftp/qftp.pro 我的项目的子项目,间接编译examples我的项目,只须要更改qftp\examples\qftp\ftpwindow.cpp中的43行,将#include <QtFtp>改为#include <QFtp>,即能够编译并运行。作为独立我的项目,除了批改1中的这项,还须要批改qftp\examples\qftp\qftp.pro中ftp库的加载形式,从第五行中删除ftp,而后减少如下代码:CONFIG(debug, debug|release) { LIBS += -lQt5Ftpd} else { LIBS += -lQt5Ftp}也就是说,ftp的加载形式还不能与Qt5的原生库完全一致,如何做到这一点,我还须要工夫钻研。 示例我的项目改良修改进度条的提前显示,对progressDialog新对象进行如下设置,去掉了勾销操作,勾销操作有问题,临时屏蔽。 progressDialog = new QProgressDialog("download...", nullptr, 0, 100, this); progressDialog->setWindowModality(Qt::WindowModal); auto winFlags = windowFlags() & ~Qt::WindowMinMaxButtonsHint; progressDialog->setWindowFlags(winFlags &~ Qt::WindowCloseButtonHint); //去掉窗口的默认按钮 progressDialog->reset(); //防止提前显示 progressDialog->setAutoClose(false); progressDialog->setAutoReset(false);屏蔽勾销按钮的音讯链接。 ...

February 2, 2021 · 1 min · jiezi

关于c++:C并发与多线程-4创建多个线程数据共享问题分析

创立和期待多个线程应用容器类简略治理多个线程。 #include <iostream>#include <thread>#include <vector>using namespace std;void thread_func(int i){ cout << "thread_func id : " << std::this_thread::get_id() << " " << i << endl;}int main(){ cout << "main begin" << endl; vector<thread> threads; for (int i=0; i<10; ++i) threads.emplace_back(thread(thread_func, i)); for (int i=0; i<10; ++i) threads.at(i).join(); cout << "main end" << endl; return 0;}输入:[输入后果每次可能是不统一的,因为子线程间竞争运行未做同步解决] main beginthread_func id : 2 0thread_func id : 3 1thread_func id : 5 3thread_func id : 6 4thread_func id : 4 2thread_func id : 8 6thread_func id : 9 7thread_func id : 7 5thread_func id : 10 8thread_func id : 11 9main end数据共享问题剖析只读多线程只读同一资源是平安的。 ...

February 2, 2021 · 2 min · jiezi

关于c++:C并发与多线程-3线程传参数详解detach-注意事项

获取线程idstd::this_thread::get_id()#include <iostream>#include <thread>using namespace std;std::thread::id main_thread_id = std::this_thread::get_id(); // 留神这里!!!void is_main_thread(){ cout << std::this_thread::get_id() << endl; // 留神这里 !! if (main_thread_id == std::this_thread::get_id()) // 留神这里 !! cout << "This is the main thread" << endl; else cout << "This is not main thread" << endl;}int main(){ is_main_thread(); thread th(is_main_thread); th.join(); return 0;}输入: 1This is the main thread2This is not main thread线程调用对象的参数传递援用作为参数援用作为参数时,产生参数拷贝而不是援用传递;同时应用 std::ref() 与 thread::detach() 时,须要思考主线程中的部分属性资源(对象)是否被子线程应用,并且主线程是否先于子线程完结。 应用 thread::detach() 主线程与子线程拆散独立运行,应用 std::ref() 子线程真正援用所传递实参。当实参在主线程中领有部分属性,并且主线程先于子线程完结,那么主线程实参资源开释,子线程的形参援用便指向未定义的资源,到这里祝贺你,驶入了通向未定义的快车道。C++ 自身有援用(&),为什么又引入 std::ref 呢?次要是思考函数式编程(如 std::thread, std::bind)在应用时,是对参数间接拷贝,而不是援用;std::thread, std::bind 一个函数模板,它的原理是依据已有的模板生成一个函数,然而因为std::thread, std::bind 不晓得生成的函数执行的时候,传递进来的参数是否还无效。所以它抉择参数传递而不是援用传递。如果援用传递,std::ref 和 std::cref 就排上用场了。#include <iostream>#include <thread>using namespace std;void thread_func(const int &i){ cout << "thread_func begin" << endl; cout << "i = " << i << endl; const_cast<int &>(i) = i * 2; cout << "i = " << i << endl; for (int i=0; i<1000; ++i) { } // 操作 obj.i ... cout << "thread_func end" << endl;}int main(){ cout << "main begin" << endl; int i1 = 10; cout << i1 << endl; thread th1(thread_func, i1); // 留神这里 i1 !!! th1.join(); // th1.detach(); // 实参 i1 被拷贝,子线程可失常运行 cout << i1 << endl; cout << "=================" << endl; int i2 = 10; cout << i2 << endl; thread th2(thread_func, std::ref(i2)); // 留神这里 std::ref(i2) !!! th2.join(); // th2.detach(); // 实参被援用,主线程完结时部分 i2 开释, 子线程援用开释资源,行为未定义! cout << i2 << endl; cout << "main end" << endl; return 0;}输入: ...

February 1, 2021 · 4 min · jiezi

关于c++:pika-hash-结构解读

title: pika hash 表 常识总结date: 2021-01-29 13:32:22author: 李朋飞tags: pikacache本文次要对 pika 中 hash 数据结构的应用做一个小结。 <!--more--> pika 是 360 开源的一个非关系型数据库,能够兼容 Redis 零碎的大部分命令。反对主从同步。次要的区别是 pika 反对的数据量不受内存的限度,仅和硬盘大小无关。底层应用了RocksDB 做 KV 数据的存储。本文次要对Pika 的hash 数据结构做个小结。 命令反对接口状态HDEL反对HEXISTS反对HGET反对HGETALL反对HINCRBY反对HINCRBYFLOAT反对HKEYS反对HLEN反对HMGET反对HMSET反对HSET暂不反对单条命令设置多个field value,如有需要请用HMSETHSETNX反对HVALS反对HSCAN反对HSTRLEN反对存储引擎在做数据存储时,pika 会把hash 数据转成一层kv 构造做存储。例如,如果执行如下命令: HSET key field value会首先创立一个 hash 的 meta kv 值,数据格式如下: 为了保留field 和 value 值,将会再创立一个kv,格局如下: 从上图能够看出,每个field 的存储,会存储 整个hash 的key以及key的版本信息。 CRUD操作CU 操作例如 Hset 操作: Status RedisHashes::HSet(const Slice& key, const Slice& field, const Slice& value, int32_t* res) { rocksdb::WriteBatch batch; // 此操作须要加锁 // 函数完结,锁解除 ScopeRecordLock l(lock_mgr_, key); int32_t version = 0; uint32_t statistic = 0; std::string meta_value; // 获取meta 数据 Status s = db_->Get(default_read_options_, handles_[0], key, &meta_value); if (s.ok()) { ParsedHashesMetaValue parsed_hashes_meta_value(&meta_value); if (parsed_hashes_meta_value.IsStale() || parsed_hashes_meta_value.count() == 0) { // 如果meta 存在,然而没有用到 // 则间接更新meta & field & value version = parsed_hashes_meta_value.InitialMetaValue(); parsed_hashes_meta_value.set_count(1); batch.Put(handles_[0], key, meta_value); HashesDataKey data_key(key, version, field); batch.Put(handles_[1], data_key.Encode(), value); *res = 1; } else { // 如果存在,且工夫未过期, 版本正确 version = parsed_hashes_meta_value.version(); std::string data_value; HashesDataKey hashes_data_key(key, version, field); // 获取field 数据 s = db_->Get(default_read_options_, handles_[1], hashes_data_key.Encode(), &data_value); if (s.ok()) { // 如果以后存的field 数据正确 *res = 0; if (data_value == value.ToString()) { // 值也相等,则不操作 return Status::OK(); } else { // 批改kv batch.Put(handles_[1], hashes_data_key.Encode(), value); statistic++; } } else if (s.IsNotFound()) { // 如果没有存在kv, 则增加,并更新meta parsed_hashes_meta_value.ModifyCount(1); batch.Put(handles_[0], key, meta_value); batch.Put(handles_[1], hashes_data_key.Encode(), value); *res = 1; } else { // 获取失败 return s; } } } else if (s.IsNotFound()) { // 若meta 未找到, 编码,写入 char str[4]; EncodeFixed32(str, 1); HashesMetaValue meta_value(std::string(str, sizeof(int32_t))); version = meta_value.UpdateVersion(); batch.Put(handles_[0], key, meta_value.Encode()); HashesDataKey data_key(key, version, field); batch.Put(handles_[1], data_key.Encode(), value); *res = 1; } else { return s; } // 最初批量写 s = db_->Write(default_write_options_, &batch); // 更新总的统计信息 UpdateSpecificKeyStatistics(key.ToString(), statistic); return s;}能够看出,在做HSet 操作时,和料想中一样,会对 metadata 和 field value 同时操作,并须要同时更新,而且须要做锁操作。因为pika是多线程的,在频繁拜访同一个hash中的数据时,会有大量的锁抵触呈现。 ...

February 1, 2021 · 5 min · jiezi

关于c++:在-WebAssembly-中实现回调的方式

本文将介绍在 C++ 中实现 js 回调的几种形式. 在应用 wasm 的过程中, 防止不了要从 C++ 回调 js 的函数来实现异步交互.官网文档 https://emscripten.org/docs/p...中曾经介绍了6种实现回调的形式, 这里介绍几种能解决理论问题的形式。 EM_ASM 相干参数介绍EM_ASM 函数簇蕴含 EM_ASMEM_ASM_INTEM_ASM_DOUBLE相似的应用形式 : EM_ASM_({ postMessage({cmd: 'callback', text: "callback", threadId: $2, callId : $0, code : $1}) }, callback, code, tid);其中&dollar;0&dollar;1&dollar;2别离代表 callback, code, tid 的值.前面两个函数还能够获取到 js 返回的 int/ double 值. 个别能满足简略的应用. 如何在 worker 中实现回调应用 wasm 的时候, 某些工作会被放到 worker 中执行, 执行实现后回调告诉后果. 这个时候要特地留神: worker 和主线程是互相独立的, 并不能像一般的多线程能够共享过程内的数据. 在 worker 中调用 js 回调时, 第一个面临的限度就是 web worker 的限度: 不能拜访 window, document 对象与主线程通信须要通过 post message 形式不能拜访主过程中的全局变量会对象如果间接在 worker 中间接调用回调, 就只能做一些简略的事件. 为此 emscripten 提供了以下函数: ...

February 1, 2021 · 1 min · jiezi

关于c++:C并发与多线程-2线程启动结束创建线程多种方法joindetach

演示线程运行的开始和完结可执行程序运行失去一个过程,过程中惟一的主线程启动,当主线程从 main 函数返回,整个进行完结。创立的子线程须要从一个初始函数开始运行,一旦函数执行结束,以后子线程完结。过程完结标记:主线程是否完结。如果主线程执行结束,则代表整个过程完结,个别状况下此时如果还有其它子线程未执行完,则子线程会被强行终止(例外:detach)。thread创立一个线程执行对象。 join阻塞主线程(调用线程),直到子线程执行完结。 注:须要保障在 joinable 返回 true 时应用(返回 false 时运行时抛出 std::system_error 异样)detach将子线程和主线程的关联拆散,子线程可驻留零碎后盾独立持续运行,主线程无奈再取得主线程的控制权,即主线程完结,子线程也不会完结。当子线程完结时,由C++运行时库负责清理线程相干的资源。 注:须要保障在 joinable 返回 true 时应用(返回 false 时运行时抛出 std::system_error 异样)joinable判断一个线程对象是否可能调用 join() 或者 detach(),能够返回 true,不能够返回 false。 Test1: thread, join, joinable #include <iostream>#include <thread>using namespace std;void thread_func(){ cout << "thread_func begin" << endl; for (uint32_t i=0; i<10000; ++i) { } cout << "thread_func end" << endl;}int main(){ cout << "main begin" << endl; thread my_thread(thread_func); if (my_thread.joinable()) // 注: 调用 join 前须要 joinable 判断!!! { cout << "my_thread.joinable() " << my_thread.joinable() << endl; my_thread.join(); } cout << "my_thread.joinable() " << my_thread.joinable() << endl; cout << "main end" << endl; return 0;}输入: ...

January 31, 2021 · 3 min · jiezi

关于c++:C程序性能优化指南

准则《More Effective C++》书中效率局部第一条就是80—20准则。说得是——大概 20%的代码应用了 80%的程序资源;大概 20%的代码耗用了大概 80%的运行工夫;大概 20%的代码应用了 80%的内存。因而,一些简略的优化也能显著进步程序性能。先实现程序性能,再思考性能优化的事,否则会呈现代码可读性差,适度形象等问题。大部分的性能优化其实都是在做工夫和空间的衡量,空间换工夫,或者工夫换空间。良好的代码格调和代码标准能无效的防止性能问题的呈现,所以codereview也很重要。咱们真正想大幅度的晋升程序性能须要借助程序分析器(profiler)寻找出程序的性能瓶颈,针对这个瓶颈进行代码层面,算法层面,架构层面等多方面的优化。罕用优化办法空间足够时,能够将常常须要读取的资源,缓存在内存中。尽量减少大内存对象的结构与析构,思考缓存临时不必的对象,期待后续持续应用。尽量应用C++11的右值语义,缩小长期对象的结构。简略的性能函数能够应用内联。少用继承,多用组合,尽量减少继承层级。在循环遍历时,优化判断条件,缩小循环次数。优化线程或过程的同步形式,能用原子操作的就不必锁。能应用层同步的就不必内核对象同步。优化堆内存的应用,如果有内存频繁的申请与开释,能够思考内存池。优化线程的应用,节俭系统资源与切换造成的性能损耗,线程应用频繁的能够思考线程池。尽量应用事件告诉,审慎应用轮循或者sleep函数。界面开发中,耗时的业务代码不要放在UI线程中执行,应用独自的线程去异步解决耗时业务,进步界面响应速度。常常重构、优化代码构造。优化算法或者架构,从设计层面进行性能的优化。

January 31, 2021 · 1 min · jiezi

关于c++:C并发与多线程-1并发基本概念及实现进程线程基本概念

并发、过程、线程的基本概念和综述并发两个或者更多的工作(独立的流动)同时产生(进行):一个程序同时执行多个独立的工作。以往计算机为单核CPU(中央处理器):某一时刻只能执行一个工作,由操作系统调度,每秒钟进行屡次“工作切换”,这并不是真正的并发。同时工作切换须要保留与复原工作上下文,存在工夫开销。随着硬件倒退,呈现了多处理器(多核)计算机,可能实现真正的并行任务解决(硬件并发)。应用并发的起因:能够同时解决多个工作,进步解决性能。 可执行程序磁盘上的一个文件: window : .exelinux :具备可执行属性的文件 (-x)过程运行一个可执行程序失去过程。过程是操作系统资源分配的根本单位。线程每个过程都有一个惟一的主线程。过程被创立时,主线程启动执行 main 函数。线程中能够持续创立其它非主线程。线程是操作系统调度的根本单位。 学习心得开发多线程程序是商用的必须需要。线程开发有肯定难度。C++线程会设计到很多新的概念。网络通讯、网络服务中多线程是肯定会被用到的。并发的实现办法通过多个过程实现并发。在独自的过程中,写代码创立除了主线程之外的其它线程实现并发。 多过程并发例:启动word和网页浏览器同时解决不同工作。过程之间的通信形式 同一电脑:管道、文件、音讯队列、共享内存、socket通信不同电脑:socket 通信多线程并发每个线程可有本人独立的运行门路同一过程中所有线程共享地址空间(共享内存)。全局变量、指针、援用等能够在线程之间传递,通信开销远远小于过程。线程并不是越多越好,线程须要独立的堆栈空间,同时线程切换时会耗费执行工夫。总结多过程并发和多线程并发能够混合应用,但倡议优先思考多线程技术。C++11 新规范线程库经典开发方式 indow: CreateThread(), _beginthread(),_beginthreadexe()linux : pthread_create();posix thread (跨平台,须要最根底配置)C++11及后续 语言层面反对多线程,意味着可跨平台,缩小开发人员工作两。

January 31, 2021 · 1 min · jiezi

关于c++:C中控制远程计算机的服务的方法

在.net中提供了一些类来显示和管制Windows零碎上的服务,并能够实现对近程计算机服务服务的拜访,如System.ServiceProcess命名空间上面的ServiceController 类,System.Management上面的一些WMI操作的类。尽管用ServiceController能够很不便的实现对服务的管制,而且很直观、简洁和容易了解。然而我认为他的性能同通过WMI来操作服务相比,那可能就有些繁多了,并且对多个服务的操作可能就比拟麻烦,也无奈列出零碎中的所有服务的具体数据。这里要讲的就是如何应用System.Management组件来操作近程和本地计算机上的服务。 WMI作为Windows 2000操作系统的一部分提供了可伸缩的,可扩大的治理架构.公共信息模型(CIM)是由分布式治理工作规范协会(DMTF)设计的一种可扩大的、面向对象的架构,用于管理系统、网络、应用程序、数据库和设施。Windows治理标准也称作CIM for Windows,提供了对立的拜访治理信息的形式。如果须要获取具体的WMI信息请读者查阅MSDN。System.Management组件提供对大量治理信息和治理事件汇合的拜访,这些信息和事件是与依据 Windows 治理标准 (WMI) 构造对系统、设施和应用程序设置检测点无关的。 然而站长博客下面并不是咱们最关怀的,上面才是咱们须要谈的话题。 毫无疑问,咱们要援用System.Management.Dll程序集,并要应用System.Management命名空间下的类,如ManagementClass,ManagementObject等。上面用一个名为Win32ServiceManager的类把服务的一些相干操作包装了一下,代码如下: using System; using System.Management; namespace ZZ.Wmi { public class Win32ServiceManager { private string strPath; private ManagementClass managementClass; public Win32ServiceManager():this(".",null,null) { } public Win32ServiceManager(string host,string userName,string password) { this.strPath = "\\"+host+"\root\cimv2:Win32_Service"; this.managementClass = new ManagementClass(strPath); if(userName!=null&&userName.Length>0) { ConnectionOptions connectionOptions = new ConnectionOptions(); connectionOptions.Username = userName; connectionOptions.Password = password; ManagementScope managementScope = new ManagementScope( "\\" +host+ "\root\cimv2",connectionOptions) ; this.managementClass.Scope = managementScope; } } // 验证是否能连贯到近程计算机 public static bool RemoteConnectValidate(string host,string userName,string password) { ConnectionOptions connectionOptions = new ConnectionOptions(); connectionOptions.Username = userName; connectionOptions.Password = password; ManagementScope managementScope = new ManagementScope( "\\" +host+ "\root\cimv2",connectionOptions) ; try { managementScope.Connect(); } ...

January 30, 2021 · 1 min · jiezi

关于c++:struct关键字与class关键字区别

惟一的区别:默认成员拜访说明符及默认派生拜访说明符。struct:默认public(私有)class:默认private(公有)

January 30, 2021 · 1 min · jiezi

关于c++:mac-vscode-c-环境配置编译debug

官网中对应的页面如下 https://code.visualstudio.com... 1 筹备vscode 软件C/C++ Extension Pack 插件 clang/clang++ 编译器 查看已装置clang++ clang++ -v如果未装置,请返回 app store 下载 xcode2 .vscode配置在当前工作区筹备以下文件(夹) .vscode tasks.json # 用于编译c++文件launch.json # 用于应用vscode自带的debug工具(左侧的小虫图标)c_cpp_properties.json # 用于应用vscode自带的代码提醒工具如 IntelliSensemain.cpp #include <iostream>#include <vector>#include <string>using namespace std;int main(){ vector<string> msg {"Hello", "C++", "World", "from", "VS Code", "and the C++ extension!"}; for (const string& word : msg) { cout << word << " "; } cout << endl;} 配置tasks.jsoncommand + shift + b,vscode会执行tasks.json中的工作。 本文配置的是c++编译,替换tasks.json的内容如下: ...

January 30, 2021 · 1 min · jiezi

关于c++:杂谈gccmake和cmake

原创: 杂谈_gcc,make和cmake gcc,make,cmake关系1.gcc是GNU Compiler Collection(就是GNU编译器套件),也能够简略认为是编译器,它能够编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。 2.当你的程序只有一个源文件时,间接就能够用gcc命令编译它。 3.然而当你的程序蕴含很多个源文件时,用gcc命令一一去编译时,你就很容易凌乱而且工作量大 4.所以呈现了make工具make工具能够看成是一个智能的批处理工具,它自身并没有编译和链接的性能,而是用相似于批处理的形式—通过调用makefile文件中用户指定的命令来进行编译和链接的。 5.makefile是什么?简略的说就像一首歌的乐谱,make工具就像指挥家,指挥家依据乐谱指挥整个乐团怎么样演奏,make工具就依据makefile中的命令进行编译和链接的。 6.makefile命令中就蕴含了调用gcc(也能够是别的编译器)去编译某个源文件的命令。 7.makefile在一些简略的工程齐全能够人工手下,然而当工程十分大的时候,手写makefile也是十分麻烦的,如果换了个平台makefile又要从新批改。 8.这时候就呈现了Cmake这个工具,cmake就能够更加简略的生成makefile文件给下面那个make用。当然cmake还有其余性能,就是能够跨平台生成对应平台能用的makefile,你不必再本人去批改了。 9.可是cmake依据什么生成makefile呢?它又要依据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。 10.到最初CMakeLists.txt文件谁写啊?亲,是你本人手写的。 11.当然如果你用IDE,相似VS这些个别它都能帮你弄好了,你只须要按一下那个三角形 12.cmake是make maker,生成各种能够间接管制编译过程的控制器的配置文件,比方makefile、各种IDE的配置文件。 13.make是一个简略的通过文件工夫戳管制主动过程、解决依赖关系的软件,这个主动过程能够是编译一个我的项目。 原文件—cmakelist —cmake —makefile —make —生成可执行文件(make中则蕴含了多条链接以及gcc/g++编译语句)。 简略了解 cmake和autotools正是makefile的下层工具,它们的目标正是为了产生可移植的makefile,并简化本人入手写makefile时的微小工作量。如果你本人入手写过makefile,你会发现,makefile通常依赖于你以后的编译平台,而且编写makefile的工作量比拟大,解决依赖关系时也容易出错。因而,对于大多数我的项目,该当思考应用更自动化一些的 cmake或者autotools来生成makefile,而不是上来就入手编写。 INCLUDE_DIRECTORIES:增加头文件目录 LINK_DIRECTORIES:增加须要链接的库文件目录 LINK_LIBRARIES:增加须要链接的库文件门路,留神这里是全门路 附录GCC 和 cmake的关系?:https://www.zhihu.com/questio... cmake疾速入门:https://blog.csdn.net/kai_zon... cmake 从放弃到入门 - 醍醐灌顶(比拟残缺的案例,强烈推荐):https://blog.csdn.net/iceboy3...cmake中的link_directories, LINK_LIBRARIES, target_link_libraries的区别:https://www.jianshu.com/p/542... Linux下gcc/g++、make和cmake的区别:https://www.cnblogs.com/bokey...

January 28, 2021 · 1 min · jiezi

关于c++:C中的类型转换下强制类型转换

在上篇与中篇中,咱们探讨了隐式类型转换及其与函数重载之间的相干话题。本篇将要探讨的即为类型转换的另一大分支——强制类型转换。 9. C格调的强制类型转换在C语言中,强制类型转换存在两种等价模式:Type(Value)或(Type)Value。 参考以下代码: int main(){ (int *) malloc(0); // (Type)Value模式的强制类型转换 int(0.); // Type(Value)模式的强制类型转换}上述代码中,咱们别离应用了C语言的提供的两种强制类型转换的等价模式将void 转为了int ,以及将double转为了int。 10. static_cast在C++中,static_cast相当于C语言中的强制类型转换语法。static_cast用于在编译期对某种类型的变量进行强制类型转换。 参考以下代码: int main(){ static_cast<int *>(malloc(0)); static_cast<int>(0.);}上述代码中,咱们应用了static_cast别离将void 转为了int ,以及将double转为了int。 11. const_castconst_cast是C++中专用于解决与const相干的强制类型转换关键字,其性能为:为一个变量从新设定其const形容。即:const_cast能够为一个变量强行减少或删除其const限定。 须要明确的是,即便用户通过const_cast强行去除了const属性,也不代表以后变量从不可变变为了可变。const_cast只是使得用户接管了编译器对于const限定的管理权,故用户必须恪守“不批改变量”的承诺。如果违反此承诺,编译器也不会因而而引发编译时谬误,但可能引发运行时谬误。 上面探讨const_cast的主要用途。 考查以下代码: struct A { A &test() { return *this; } };int main(){ A().test();}这段代码看上去运行失常。但如果: struct A { A &test() { return *this; } };int main(){ const A a; a.test(); // Error!}咱们试图用一个const对象去调用非const成员函数,此时,为了调用此成员函数,const A this就须要转换为A this,这显然是不行的。 通过上述探讨,咱们能够将代码批改为如下: struct A { const A &test() const { return *this; } };int main(){ const A a; a.test();}咱们将this指针申明为const A ,解决了此问题。但不难发现,如果咱们通过一个非const对象调用此办法,其返回值也会被转为const,从而不再能够持续调用任何承受A this的成员函数。这显著不是咱们想要的后果: ...

January 28, 2021 · 2 min · jiezi

关于c++:C中的类型转换中隐式类型转换与函数重载

在上篇中,咱们探讨了C++中与隐式类型转换相干的一些话题,而函数重载是与隐式类型转换相干的又一大重要话题,本篇将要探讨的内容即为隐式类型转换与函数重载之间的相干话题。 6. 隐式类型转换与重载确定C++中,如果同时定义了多个函数名称雷同,但函数签名不同的函数,则此行为称为函数重载。调用重载函数时,编译器将依据调用的参数数量与类型确定被调用的是哪一个函数,此过程称为重载确定。在重载确定过程中,如果编译器发现不止一个函数都是以后调用的最佳版本,则将引发二义性编译时谬误。 须要申明的是:重载确定是一个非常复杂的话题,本文没有对重载确定的所有状况进行详尽的阐述,而只是提出了其中一些与隐式类型转换关联较大的,或具备代表性的话题进行阐述。 首先,援用《C++ Primer》中对于重载确定的隐式类型转换等级的阐明: 为了确定最佳匹配,编译器将实参类型到形参类型的转换划分成几个等级,具体排序如下所示: 准确匹配,包含以下状况:实参类型和形参类型雷同实参从数组类型或函数类型转换成对应的指针类型向实参增加顶层const或从实参中删除顶层const通过const转换实现的匹配通过类型晋升实现的匹配通过算术类型转换或指针转换实现的匹配通过类类型转换实现的匹配依据这段内容,咱们能够失去以下要点: 数组向指针,以及函数向函数指针的隐式类型转换并不被C++视为隐式类型转换,其只是语法上的差异显然,顶层const在不同变量之间不存在传递性波及底层const的类型转换被视为最靠近准确匹配的隐式类型转换类型晋升优先于算术类型转换自定义的类型转换等级最低,且各种自定义类型转换之间无先后差异咱们首先来看一个最简略的例子: void test(int) {}void test(int, int = 0) {}int main(){ test(0); // 调用哪一个test?}上述代码中,咱们仅通过一个int调用了test函数,此时,编译器无奈确定调用的函数版本应该是void test(int)还是void test(int, int = 0),所以此调用是具备二义性的。 再来看一个依据形参类型进行重载确定的例子: void test(int) {}void test(double) {}int main(){ test(0); // void test(int) test(0.); // void test(double) test('0'); // void test(int),因为char -> int比char -> double更优}上述代码中,显然,test(0)调用是void test(int)版本的准确匹配,且test(0.)调用是void test(double)版本的准确匹配。考查test('0'),因为char -> int属于类型晋升,其比char -> double更优,故编译器抉择了void test(int)版本,并将char通过隐式类型转换转为int。 接下来探讨用户自定义的类型转换与重载确定之间的关系。 首先,C++对于隐式类型转换有一条十分重要的规定:对于单次隐式类型转换,用户定义的隐式类型转换计划与算术类型转换各可呈现一次,且程序不限。 围绕此条性质,首先能够失去的论断是:不容许呈现不止一次的用户定义的隐式类型转换。 参考以下代码: // 定义A -> B -> C的隐式类型转换struct A {};struct B { B(const A &) {} };struct C { C(const B &) {} };int main(){ B b = A(); // A -> B C c1 = A(); // Error! 不能够间断应用两次自定义的隐式类型转换 C c2 = B(A()); // B -> C}上述代码中,应用A类对象对B类变量赋值是可行的,因为咱们定义了A -> B的转换构造函数,但如果咱们试图通过多个转换构造函数实现A -> B,而后B -> C的隐式类型转换,则会引发编译时谬误。 ...

January 28, 2021 · 3 min · jiezi

关于c++:C中的类型转换上隐式类型转换

0. 引言不同的数据在计算机内存中的存储形式不同,导致了“类型”这一抽象概念的呈现。对于一个变量而言,其必须要答复三个问题: 在哪能够拜访到这个变量的终点?从终点向后须要读取多少内存?应该如何解析读取到的二进制数据?上述的三个问题中,问题1,由内存地址答复,问题2和3,均由类型答复。由此可见,类型与内存地址独特形成了一个变量的残缺组分。之所以不能对void *取值,也是因为无法回答问题2和3导致。 进一步的,咱们能够失去一条非常重要的论断:对于两个不同类型的变量,因为其对问题2和3的答案不同,故如果将这样的两个变量间接进行运算,在绝大多数状况下都将无奈产生有价值的计算结果。故在简直所有的编程语言中都有一条重要的规定:不同类型的两个变量无奈间接进行运算。 尽管不同类型的两个变量无奈进行运算,但显然,咱们可将其中的一个变量通过类型转换,转为与另一个变量类型统一,此时就满足“同类型变量能力进行运算”这一规定了。同时,因为某些类型转换是“理所应当”的,而另一些不是,故由此又派生出两个概念:隐式类型转换与显式类型转换。隐式类型转换指不通过专门的类型转换操作,而是通过其余规定或代码上下文隐式产生的类型转换,而显式类型转换则通过专门的类型转换操作进行转换,显式类型转换具备强制性,其将不受任何类型转换以外的因素影响,故显式类型转换又称为强制类型转换。 在C++中,类型转换是一个非常复杂的话题。本文将先从隐式类型转换动手,逐渐探讨各类C++的类型转换话题。 1. 类型晋升与算术类型转换算术类型转换专指C++提供的各种内置算术类型之间的隐式类型转换。内置算术类型次要包含以下类型: boolchar, signed char, unsigned charshort, int, long, long long, unsigned short, unsigned int, unsigned long, unsigned long longfloat, double, long doublesize_t, ptrdiff_t, nullptr_t等其余非凡类型算术类型转换是一类不齐全明确的,且与底层密切相关的隐式类型转换。其遵循以下几条次要准则: 对于同类算术类型,如short与int,float与double,占用较小内存的类型将转换成另一类型。如short + int将被转换为int + int。此种类型转换称为类型晋升。整形将转为浮点型。如int + double将被转换为double + double。仅当无符号类型占用的内存小于有符号类型时,无符号类型将产生类型晋升从而转为有符号类型,否则,有符号类型将转为无符号类型。这是一个十分须要留神的点。参考以下代码: int main(){ unsigned short a = 1; unsigned b = 1; cout << (a > -1) << " " << (b > -1) << endl; // 1 0!}上述代码中,-1作为int间接量而存在,因为变量a是unsigned short类型,故其将被转为int,值仍为1。但因为变量b的类型是与int同级的unsigned类型,故此时-1将被转为unsigned类型,这显著不是咱们须要的后果。由此可见,当有符号类型与无符号类型(如size_t)产生混用时,肯定要小心可能会产生的隐式类型转换。 ...

January 28, 2021 · 2 min · jiezi

关于c++:CS144-Lab-Assignments-手写TCP-LAB1

CS 144: Introduction to Computer Networking, Fall 2020https://cs144.github.io/My Repohttps://github.com/wine99/cs1... 工作 TCP 接受方接管到乱序且可能重叠的报文段,StreamReassembler 须要将收到的报文段按状况送入 ByteStream (lab0 实现的),或抛弃,或暂存(在适合的时候重组送入 ByteStream)。 留神点: 报文段蕴含索引、长度、内容,lab1 的索引从 0 开始增长,不会溢出绕回。任何报文段,包含新收到的和暂存的,只有能够,就应该立即送入 ByteStream(可能须要手动重组和去重叠)。容量的限度如下图所示。 思路用 set 来暂存报文段,依照报文段的 index 大小比照重载 < 运算符。用 _eof 来保留是否曾经收到过有 EOF 标识的段。收到新段时,通过比照新段的 index、length 和 _first_unacceptable,_first_unassembled 对新段进行必要的剪切,而后解决重叠(调用 _handle_overlap)。解决重叠的逻辑:遍历每个暂存段,如果与新段产生重叠,合并暂存段与新段(调用 _merge_seg,总是往新段上合并,合并后删除重叠的暂存段)。合并段的办法:分类探讨,两个段总共会有四种不同的重叠状况,别离解决。解决完重叠后,调用 _stitch_output:遍历所有暂存段,将可合并的暂存段接入 ByteStream 中。最初,当 _eof 为真且 unassembled_bytes 为 0 时,调用 ByteSteram 的 end_input。代码stream_reassembler.hh: class StreamReassembler { private: // Your code here -- add private members as necessary. ByteStream _output; //!< The reassembled in-order byte stream size_t _capacity; //!< The maximum number of bytes size_t _first_unread = 0; size_t _first_unassembled = 0; size_t _first_unacceptable; bool _eof = false; struct seg { size_t index; size_t length; std::string data; bool operator<(const seg t) const { return index < t.index; } }; std::set<seg> _stored_segs = {}; void _add_new_seg(seg &new_seg, const bool eof); void _handle_overlap(seg &new_seg); void _stitch_output(); void _stitch_one_seg(const seg &new_seg); void _merge_seg(seg &new_seg, const seg &other); public:stream_reassembler.cc: ...

January 25, 2021 · 5 min · jiezi

关于c++:stdasync的使用总结

C++98规范中并没有线程库的存在,直到C++11中才终于提供了多线程的规范库,提供了治理线程、爱护共享数据、线程间同步操作、原子操作等类。多线程库对应的头文件是#include <thread>,类名为std::thread。 然而线程毕竟是比拟贴近零碎的货色,应用起来依然不是很不便,特地是线程同步及获取线程运行后果上就更加麻烦。咱们不能简略的通过thread.join()失去后果,必须定义一个线程共享的变量来传递后果,同时还要思考线程间的互斥问题。好在C++11中提供了一个绝对简略的异步接口std::async,通过这个接口能够简略的创立线程并通过std::future中获取后果。以往都是本人去封装线程实现本人的async,当初有线程的跨平台接口能够应用就极大的不便了C++多线程编程。 先看一下std::async的函数原型 //(C++11 起) (C++17 前)template< class Function, class... Args>std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>> async( Function&& f, Args&&... args );//(C++11 起) (C++17 前)template< class Function, class... Args >std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>> async( std::launch policy, Function&& f, Args&&... args ); 第一个参数是线程的创立策略,有两种策略可供选择: std::launch::async:在调用async就开始创立线程。std::launch::deferred:提早加载形式创立线程。调用async时不创立线程,直到调用了future的get或者wait时才创立线程。默认策略是:std::launch::async | std::launch::deferred也就是两种策略的合集,具体什么意思前面具体再说 第二个参数是线程函数 线程函数可承受function, lambda expression, bind expression, or another function object 第三个参数是线程函数的参数 不再阐明 返回值std::future std::future是一个模板类,它提供了一种拜访异步操作后果的机制。从字面意思上看它示意将来,这个意思就十分贴切,因为她不是立刻获取后果然而能够在某个时候以同步的形式来获取后果。咱们能够通过查问future的状态来获取异步操作的构造。future_status有三种状态: deferred:异步操作还未开始ready:异步操作曾经实现timeout:异步操作超时,次要用于std::future<T>.wait_for()示例: //查问future的状态std::future_status status;do { status = future.wait_for(std::chrono::seconds(1)); if (status == std::future_status::deferred) { std::cout << "deferred" << std::endl; } else if (status == std::future_status::timeout) { std::cout << "timeout" << std::endl; } else if (status == std::future_status::ready) { std::cout << "ready!" << std::endl; }} while (status != std::future_status::ready); std::future获取后果的形式有三种: ...

January 25, 2021 · 2 min · jiezi

关于c++:CS144-Lab-Assignments-手写TCP-LAB0-LAB1

CS 144: Introduction to Computer Networking, Fall 2020https://cs144.github.io/My Repohttps://github.com/wine99/cs1... LAB0 在 master 分支,LAB1 - 7 在对应名字的分支。 webgetWhat is webget?参照 lab0.pdf 2.1 Fetch a Web page, 如下所示。 其成果等同于 Write Webget参考 API 文档 https://cs144.github.io/doc/l...。 留神 lab0.pdf 中的几点提醒: Please note that in HTTP, each line must be ended with “rn” (it’s not sufficient to use just “n” or endl).Don’t forget to include the “Connection: close” line in your client’s request. This tells the server that it shouldn’t wait around for your client to send any more requests after this one. Instead, the server will send one reply and then will immediately end its outgoing bytestream (the one from the server’s socket to your socket). You’ll discover that your incoming byte stream has ended because your socket will reach “EOF” (end of file) when you have read the entire byte stream coming from the server. That’s how your client will know that the server has finished its reply.Make sure to read and print all the output from the server until the socket reaches “EOF” (end of file) — a single call to read is not enough.void get_URL(const string &host, const string &path) { // Your code here. // You will need to connect to the "http" service on // the computer whose name is in the "host" string, // then request the URL path given in the "path" string. // Then you'll need to print out everything the server sends back, // (not just one call to read() -- everything) until you reach // the "eof" (end of file). // cerr << "Function called: get_URL(" << host << ", " << path << ").\n"; // cerr << "Warning: get_URL() has not been implemented yet.\n"; TCPSocket sock1; sock1.connect(Address(host, "http")); sock1.write("GET " + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); while (!sock1.eof()) { cout << sock1.read(); } sock1.close();}An in-memory reliable byte stream留神上面代码中的 buffer_size 为缓冲的内容大小(等于 _stream.size()),capacity 才是缓冲的大小。只有当 input_ended 为真并且 buffer_size 为 0 时,才是 EOF。 ...

January 24, 2021 · 4 min · jiezi

关于c++:TARS-染色日志|收集记录特定日志

作者|Eaton 导语| 记日志能够说是程序猿/媛日常开发中的粗茶淡饭了。在日常业务场景中,常常须要剖析特定用户的日志,个别的日志记录形式很难满足需要,有什么解决办法呢?TARS 框架中蕴含染色日志的性能,可能记录特定用户的日志,优雅地解决这一问题。本文将会介绍染色日志的原理和性能,以及如何在 TARS 中应用染色日志。 目录背景初识染色日志TARS 染色性能概述染色日志初体验 被动关上染色日志被动关上染色日志增加特定逻辑总结背景很多业务场景中,须要对特定用户的行为进行追踪,比方局部用户反馈服务有 BUG,须要排查,但发现只是个例,要独自找出这些用户的日志进行剖析;又或是 APP 上线了一个新的性能,先对一部分用户凋谢进行测试,须要追踪这部分用户的行为等。 依照个别形式,要在曾经记录的日志中检索这部分用户的日志。看起来挺简略,然而在微服务的大背景下,服务间调用关系简单(如下图),日志扩散在各个服务节点上。对于一次调用,须要先获取调用链,再找出具体服务调用的节点,而后从节点上获取日志,这个过程十分繁琐。 另外,日志的记录会耗费程序的性能,占用用户的计算资源。因而在正式环境中,日常业务都会管制日志打印的量,确保日志打印不影响用户服务。而在对特定用户行为进行剖析时,往往须要记录额定的日志,能力满足剖析等需要,间接减少日志的打印显然不太事实。 可见,传统的日志记录形式无奈满足对特定用户行为的日志记录,染色日志就是来解决这一问题的。 初识染色日志什么是染色日志呢?在一个调用链外面,标记出某个特定需要的过程,让整个调用链里的上下文信息始终被传输上来,就像一开始被标记染色一样,这种标记日志的形式,咱们叫它染色日志。 简略来说,就是咱们只想要某几个用户的日志信息,通过染色日志把这几个用户的日志另外打印一份,并收集在同一个中央,这样咱们在一个中央就能查找到这些染色用户的日志。 咱们能够用染色日志定位一些特定的地位,也能够定一些特定的逻辑。比方某微信用户反馈语音发送存在问题,通过对用户ID(微信号)进行染色,后端服务接管到染色用户的申请后,就会将该用户本次调用的处理过程日志打印进去,能够十分不便地获取咱们须要的要害信息。除了打印日志,还能够通过染色执行特定逻辑,比方新上线一个性能,凋谢给一部分用户应用,通过染色,后端服务能够判断用户是否在测试名单中,再执行相应的服务逻辑。 TARS 染色性能概述TARS 框架反对染色日志性能,能够在某服务某接口中对特定用户号码的音讯进行染色,不便地实时观察该用户引起后续所有相干调用音讯流的日志。下图为 TARS 中的染色流程 染色日志关上后,在业务中通过指定染色的 key 值,例如指定 QQ 号为 123456 的用户,后续该用户的申请都会在框架中被主动染色,并通过日志服务(tarslog)集中打印染色日志。 咱们只须要到 tarslog 服务所在的服务器上查看相应的染色日志即可,具体的门路个别为 /usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/该目录下个别蕴含两种日志文件:染色的滚动日志和染色的按天日志,日志文件名格局别离为 tars_dyeing.dyeing_roll_yyyymmdd.log, tars_dyeing.dyeing_day_yyyymmdd.log,比方: # 染色滚动日志tars_dyeing.dyeing_roll_20201103.log# 染色按天日志tars_dyeing.dyeing_day_20201103.log滚动日志是服务的本地日志,个别用于记录服务调试信息;按天日志是服务的近程日志,个别用于记录重要的业务信息。开启染色后,如果接管到染色的申请,两种日志都会额定打印一份到 tarslog,只记录染色申请打印的日志,每天保留一个文件。对于滚动日志和按天日志的用法以及更多信息,能够看到官网文档中日志局部,这里不再赘述。 染色日志初体验TARS 框架的染色日志有被动关上和被动关上两种形式。接下来让咱们通过实例,理解如何通过这两种形式在 TARS 中应用染色日志。本章中应用的实例源码都能够在这里找到。 被动关上染色日志被动关上,指的是在发动申请的客户端的业务代码中,被动关上框架的染色日志开关。具体流程如下: 在客户端程序适当的中央申明染色日志开关 tars::TarsDyeingSwitch 的对象。调用该开关对象的 enableDyeing 办法即可关上染色日志。被调用的服务也会主动关上染色开关,并打印日志到 tarslog。如果该被调服务还要调用其余服务,则主动传递给下个服务。在染色日志开关敞开前,客户端打印的所有日志和被调用的服务打印的日志,都会额定打印一份到日志服务 tarslog。客户端开关对象析构,染色日志敞开,后续的调用和日志打印不再生成染色日志。上面,咱们通过一个实例来理解如何在客户端(主调方)中被动关上染色日志。 实例这里以 C++ 为例,依照方才介绍的流程,开启染色日志并调用 TARS 服务。 在开始之前,咱们须要先筹备一个 TARS 服务,供之后的客户端调用,源码见 TestServer 源码。咱们创立一个服务,利用名为 TestApp,服务名 TestServer,Obj 名为 Test,Test.tars 文件中定义的接口如下 ...

January 22, 2021 · 4 min · jiezi

关于c++:c关键字typeid

typeid是c++的一个关键字,typeid操作符的返回后果是规范库类型type_info对象的援用。然而,C++规范并没有明确定义type_info,其具体实现依赖于各个编译器。规范只规定了typeid操作符必须实现如下四种操作:操作阐明t1 == t2如果两个对象t1和t2类型雷同,则返回true;否则返回falset1 != t2如果两个对象t1和t2类型不同,则返回true;否则返回falset.name()返回类型的C-style字符串。由编译器决定,不肯定就是实在的类型名t1.before(t2)判断t1是否位于t2的后面。类型排列程序与编译器相干,基类不肯定位于派生类的后面。type_info的成员函数name返回类型的C-style字符串,但这个返回的类型名与程序中应用的相应类型名不肯定统一,其返回值的实现由编译器决定,规范只要求每个类型返回的字符串是惟一的。和sizeof操作符相似,typeid的操作对象既能够是数据类型,也能够是表达式。应用typeid判断各种类型示例代码如下:#include<iostream> #include <typeinfo> using namespace std; class Base{};class Derived:public Base{};void func1();int func2(int n);int main() { int a = 10; int* b = &a; float c; double d; cout << typeid(a).name() << endl; cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; cout << typeid(d).name() << endl; cout << typeid(Base).name() << endl; cout << typeid(Derived).name() << endl; cout << typeid(func1).name() << endl; cout << typeid(func2).name() << endl;} Mac下应用clang++编译运行后果如下:iPifd4Base7DerivedFvvEFiiE不像Java、C#等动静语言,C++运行时能获取到的类型信息十分无限,规范也定义的很含糊,如同“鸡肋”个别。在理论工作中,咱们个别只应用type_info的“==”运算符来判断两个类型是否雷同。再来看看上面的示例代码:#include<iostream> #include <typeinfo> using namespace std; class Base{};class Drived: public Base{};int main(){ Base* pb; Drived d; pb = &d; if(strcmp(typeid(*pb).name(), typeid(Base).name()) == 0) { cout << "this is Base" << endl; } else if(strcmp(typeid(*pb).name(), typeid(Drived).name()) == 0) { cout << "this is Drived" << endl; } if(strcmp(typeid(d).name(), typeid(Base).name()) == 0) { cout << "this is Base" << endl; } else if(strcmp(typeid(d).name(), typeid(Drived).name()) == 0) { cout << "this is Drived" << endl; }}Mac下应用clang++编译运行后果如下:this is Basethis is Drived从运行后果中能够看出,即应用基类指针指向派生类,但应用typeid判断的基类指针类型仍然是基类指针。因而咱们不能用typeid来判断基类指针理论指向的是否是某个派生类。

January 15, 2021 · 1 min · jiezi

关于c++:C的各种编译错误

error C2760:语法错误: 意外的令牌“标识符”,预期的令牌为“类型说明符”解决办法: C/C++ -> 语言 -> 合乎模式,批改为否

January 15, 2021 · 1 min · jiezi

关于c++:组合Composite模式-in-C

组合模式,将对象组合成树形构造以示意“局部-整体”的层次结构,组合模式使得用户对单个对象和组合对象的应用具备一致性。ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ ——Erich Gamma et. al.伊始组合(Composite)模式,又叫作局部-整体模式,它是一种将对象组合成树状的层次结构的模式,用来示意“局部-整体”的关系,使用户对单个对象和组合对象具备统一的拜访性。 构造模型 ■ Component:形象的组件对象,为组合中的对象申明接口,让客户端能够通过这个接口来拜访和治理整个对象构造,能够在外面为定义的性能提供缺省的实现。■ Leaf:叶子节点对象,定义和实现叶子对象的行为,不再蕴含其余的子节点对象。■ Composite:组合对象,通常会存储子组件,定义蕴含子组件的那些组件的行为,并实现在组件接口中定义的与子组件无关的操作。■ Client:客户端,通过组件接口来操作组合构造外面的组件对象。 实现域Component定义struct Component { virtual ~Component(){} ABSTRACT(void process()); virtual void add(Component*) { return; } virtual void remove(Component*) { return; }};留神,下面ABSTRACT是一个C++封装宏,示意定义的办法是纯虚函数,亦即接口,原型如下: #define ABSTRACT(...) virtual __VA_ARGS__ = 0因为叶子对象没有add和remove办法的,这里在抽象类提供了一份默认实现。 叶子对象Leaf定义struct Leaf : Component { OVERRIDE(void process()) { /* do process self */ }};其中,下面OVERRIDE也是一个C++封装宏,示意实现或者覆写父类的接口(或办法),原型如下: #define OVERRIDE(...) virtual __VA_ARGS__ override组合对象Composite定义using Components = std::list<Component*>;struct Composite : Component { explicit Composite(const std::string& name) : name_{name} {} OVERRIDE(void process()) { /* do process self */ /* process child */ for (auto& c : components_) { c->process(); } } OVERRIDE(void add(Component* component)) { components_.push_back(component) } OVERRIDE(void remove(Component* component)) { components_.remove(component) }private: std::string name_; Components components_;};用户应用这里假如用户须要设计一个治理商品类别树的场景,如下 ...

January 13, 2021 · 1 min · jiezi

关于c++:select连接数限制-poll-epoll没有

fd_set构造体的定义理论蕴含的是fds_bits位数组,其大小固定,由FD_SETSIZE指定(/usr/include/bits/typesizes.h中),在以后内核中数值为1024,可见每次select零碎调用可监听解决的文件描述符最大数量为1024。poll 是链表 实践增长没问题epoll 是个红黑树,扩大树叶也没问题

January 6, 2021 · 1 min · jiezi

关于c++:魔性的float浮点数精度问题

从一个问题引入如果你以前接触过C语言,那么对上面的这段代码肯定很相熟: #include <stdio.h>int main(void){ float f_num1 = 21.75; float f_num2 = 13.45; printf("f_num1 = %f\n", f_num1); printf("f_num2 = %f\n", f_num2); printf("f_num1 + f_num2 = %f\n", f_num1 + f_num2); return 0;}置信很多人不必运行,可能间接报出答案, f_num1 = 21.75, f_num2 = 13.45, f_num1 + f_num2 = 35.2,无论是从常识还是实践角度都不难理解。 上面咱们运行一下程序,验证咱们的猜想正不正确: f_num1 = 21.750000f_num2 = 13.450000f_num1 + f_num2 = 35.200001f_num1和f_num2的后果和咱们料想的一样,之所以前面多了四个0,是因为%f默认保留6位有效数字。然而f_num1 + f_num2的后果是什么鬼,这个35.200001是从哪里来的? 是不是一下子颠覆了咱们的认知? 惊不惊喜,意不意外,刺不刺激?是不是发现自从学了C语言,连简略的算术都不会算了? 别急,还有更令你解体的。 如果是C++呢上面咱们看看以上程序的C++版本: #include<iostream>using namespace std;int main(void){ float f_num1 = 21.75; float f_num2 = 13.45; cout << "f_num1 = " << f_num1 << endl; cout << "f_num2 = " << f_num2 << endl; cout << "f_num1 + f_num2 = " << f_num1 + f_num2 << endl; return 0;}间接来看输入后果吧: ...

January 2, 2021 · 2 min · jiezi

关于c++:C学习杂记1公有派生私有派生保护派生

前言第一次在网上公布文字内容,之前始终想做,但因为各种事件耽搁或者本人没有勇气键入第一个字符而始终迁延。为了使本人所学的常识可能零碎的保留,这件事也非做不可了。本文属于一个系列内容,即《C++学习杂记》,各文章不会像《C++ primer》那样有序而齐备,只是为了记录本人遇到问题时波及的相干概念的论述。 本系列第一篇文章讲述的是C++中各种继承的个性,包含私有继承、公有继承、爱护继承。 各种继承个性实际上,对于C++继承的个性齐全能够由一张表来论述(摘抄自私有继承,公有继承,爱护继承的区别)如表1所示,对一个类来说,蕴含三种成员:公有成员、私有成员、爱护成员。上面别离围绕三种派生进行探讨。 1.私有派生模式:class a : public b基类公有成员:是不能被拜访的,基类的公有成员只能被基类的成员函数拜访到,或者是申明为友元函数(类)才能够拜访基类私有成员:是能够拜访的,即私有派生类的实例可间接调用基类的私有成员(变量或函数等)基类爱护成员:也是能够拜访的,但只能在类定义中的成员函数能够调用,不能在内部通过私有派生类的实例进行调用 2.公有派生模式:class a : private b基类公有成员:也是不能被拜访的,理由同上基类私有成员:对于公有派生类,即便基类的成员为私有,在公有派生的条件下,也全变成公有。意思是类的成员函数能够调用,在里面不能通过实例来间接调用基类爱护成员:间接把基类的爱护成员变换成公有的,后续解决同上 3.爱护派生模式:class a : protected b基类公有成员:同样,也是不能拜访的,理由同上基类私有成员:对于爱护派生,将基类的私有成员变成爱护派生类的爱护成员基类爱护成员:基类的爱护成员转变为爱护派生类的爱护成员

December 30, 2020 · 1 min · jiezi

关于c++:C-变量零初始化需要注意的问题

在咱们刚开始学习 C 语言的时候,就被教诲过:“变量在应用前必须要初始化,很多bug都来自于未应用了未初始化的变量,因为某些编译器调配空间时,默认值并不为0。”变量的零初始化是一个很一般的需要,但正是这个看起来很常见的需要,其实有很多须要留神的问题。 对于繁多规范数据类型的零初始化,咱们在定义变量的时候间接在前面加一句 = 0 就好了。但构造呢?每个构造变量一一设置为0?数组呢?循环设置为0?这些写法太啰嗦了,而且效率很低,咱们须要一种更为简洁的办法。 memset这是 C 语言时代就有的函数,但直至今日,依然有大量的 C++ 程序员依然应用 memset 来进行变量的零初始化工作。 这是用最原始的办法循环零初始化一个数组,显得十分的蠢笨: int a[10];for (int i=0;i<10;I++) a[i] = 0;而与之绝对的, memset 只有一行就搞定了: memset(a, 0, 10*sizeof(int));甚至更进一步能够简化为: memset(a, 0, sizeof(a));编译器会帮咱们计算 a 到底是多大。 memset 能够不便的清空一个构造类型的变量或数组,而让你不须要关怀外面的细节,所以这种用法应用的十分遍及。 坑1,对 const 数据执行 memsetvoid f1(char* a, size_t len){ // ... memset(a, 0, len); // ...}int main(){ const char* a = "Hello World"; f1((char*)a, strlen(a)); return 0;}a 是一个 const char 类型的字符串指针,但 f1 函数须要的是一个 char 类型的指针,兴许 f1 函数是一个第三方库外面的函数,你为了让程序编译通过,调用 f1 时对 a 做了强制类型转换,但其实在 f1 函数外部对 a 执行了 memset,这时候程序会就会解体。 ...

December 30, 2020 · 3 min · jiezi

关于c++:2020年7月B组C蓝桥杯真题试水

哇!刚刚忽然发现我的那篇扩大欧几里得达到了500+的浏览量,开森森~ 看起来致力就是有回报的嘛!用心写的文章和不用心写的文章置信宽广程序员萌都一眼看得出来撒~高兴!你们的关注和点赞是我最大的能源嗷!┗|`O′|┛ 好了,闲话不多说~ 正片开始! A.跑步训练 这个题集体不倡议写程序,间接手算就好了,然而要留神的是,每一轮-600而后+300,就相当于-300,然而!肯定要记得这-300的工夫是120s,而不是60s,手算党千万要小心!查看查看再查看,这个分丢得相当不值得。后果:3880 B.纪念日日期题目年年有,一点都不稀奇~关键在于疾速A,据说C++算日期很麻烦,谁要咱也不是Java选手呢,害,鱼和熊掌⑧可兼得嘛,祭上大杀器——计算器!后果:52038720 C.合并检测这个题,数学功底相当强 懒得写程序的我,间接手算!后果:10 D.REPEAT程序先说好啊,这玩意不是依照样例算的,实战的时候人家是给了数据的,是一个txt文件,那玩意长的,保障你放弃硬写出这些个循环的想法。我从新梳理了一遍带佬的思路,而后附上了具体正文 `#include <bits/stdc++.h>using namespace std;const int N = 1e5 + 10;char str[N];int a[N], b[N];//a用来寄存以后行层的缩进格数,b用来寄存以后层的循环次数int main(int argc, char const *argv[]){ int pos = 0, p = 0, w = 1, ans = 0;//pos存第几层循环,p存每行后面的空格数,w是总的循环数,ans存后果 a[0] = -1, b[0] = 1; freopen("prog.txt","r",stdin);//就是将规范输出流重定向到这个txt文件中, //从文件中获取输出 gets(str);//首行的“A=0”不须要 while(gets(str)){ int len = strlen(str); p = 0;//每次p都要归零啊 while(str[p] == ' ') p++; while(p <= a[pos]) w /= b[pos--];//阐明退出了最近的那一层 if(str[len - 1] == ':'){//是REPEAT语句 int k = str[len - 2] - '0';//以后循环反复的次数 w *= k; pos ++;//来到新的一层 a[pos] = p, b[pos] = k; }else {//不是循环语句 int k = str[len - 1] - '0';//要加上的数 ans += w * k; } } cout<<ans<<endl; return 0;}` * 1* 2* 3* 4* 5* 6* 7* 8* 9* 10* 11* 12* 13* 14* 15* 16* 17* 18* 19* 20* 21* 22* 23* 24* 25* 26* 27* 28* 29* 30* 31后果:241830 ...

December 28, 2020 · 5 min · jiezi

关于c++:快速排序算法CC

疾速排序算法思维疾速排序的根本思维:通过一趟排序将待排记录分隔成独立的两局部,其中一部分记录的关键字均比另一部分的关键字小,则可别离对这两局部记录持续进行排序,以达到整个序列有序。 实现原理2.1、设置两个变量 low、high,排序开始时:low=0,high=size-1。2.2、整个数组找基准正确地位,所有元素比基准值小的摆放在基准后面,所有元素比基准值大的摆在基准的前面 默认数组的第一个数为基准数据,赋值给key,即key=array[low]。因为默认数组的第一个数为基准,所以从前面开始向前搜寻(high–),找到第一个小于key的array[high],就将 array[high] 赋给 array[low],即 array[low] = array[high]。(循环条件是 array[high] >= key;完结时 array[high] < key)此时从后面开始向后搜寻(low++),找到第一个大于key的array[low],就将 array[low] 赋给 array[high],即 array[high] = array[low]。(循环条件是 array[low] <= key;完结时 array[low] > key)循环 2-3 步骤,直到 low=high,该地位就是基准地位。把基准数据赋给以后地位。2.3、第一趟找到的基准地位,作为下一趟的分界点。2.4、递归调用(recursive)分界点前和分界点后的子数组排序,反复2.2、2.3、2.4的步骤。2.5、最终就会失去排序好的数组。 动静演示 残缺代码三个函数基准插入函数:int getStandard(int array[],int low,int high)(返回基准地位下标)递归排序函数:void quickSort(int array[],int low,int high)主函数:int main() `#include <stdio.h>#include <stdlib.h>void display(int* array, int size) { for (int i = 0; i < size; i++) { printf("%d ", array[i]); } printf("n");}int getStandard(int array[], int i, int j) { // 基准数据 int key = array[i]; while (i < j) { // 因为默认基准是从右边开始,所以从左边开始比拟 // 当队尾的元素大于等于基准数据 时,就始终向前移动 j 指针 while (i < j && array[j] >= key) { j--; } // 当找到比 array[i] 小的时,就把前面的值 array[j] 赋给它 if (i < j) { array[i] = array[j]; } // 当队首元素小于等于基准数据 时,就始终向后移动 i 指针 while (i < j && array[i] <= key) { i++; } // 当找到比 array[j] 大的时,就把后面的值 array[i] 赋给它 if (i < j) { array[j] = array[i]; } } // 跳出循环时 i 和 j 相等,此时的 i 或 j 就是 key 的正确索引地位 // 把基准数据赋给正确地位 array[i] = key; return i;}void QuickSort(int array[], int low, int high) { // 开始默认基准为 low if (low < high) { // 分段地位下标 int standard = getStandard(array, low, high); // 递归调用排序 // 右边排序 QuickSort(array, low, standard - 1); // 左边排序 QuickSort(array, standard + 1, high); }}// 合并到一起疾速排序// void QuickSort(int array[], int low, int high) {// if (low < high) {// int i = low;// int j = high;// int key = array[i];// while (i < j) {// while (i < j && array[j] >= key) {// j--;// }// if (i < j) {// array[i] = array[j];// }// while (i < j && array[i] <= key) {// i++;// }// if (i < j) {// array[j] = array[i];// }// }// array[i] = key;// QuickSort(array, low, i - 1);// QuickSort(array, i + 1, high);// }// }int main() { int array[] = {49, 38, 65, 97, 76, 13, 27, 49, 10}; int size = sizeof(array) / sizeof(int); // 打印数据 printf("%d n", size); QuickSort(array, 0, size - 1); display(array, size); // int size = 20; // int array[20] = {0}; // 数组初始化 // for (int i = 0; i < 10; i++) { // 数组个数 // for (int j = 0; j < size; j++) { // 数组大小 // array[j] = rand() % 1000; // 随机生成数大小 0~999 // } // printf("原来的数组:"); // display(array, size); // QuickSort(array, 0, size - 1); // printf("排序后数组:"); // display(array, size); // printf("n"); // } return 0;}` * 1* 2* 3* 4* 5* 6* 7* 8* 9* 10* 11* 12* 13* 14* 15* 16* 17* 18* 19* 20* 21* 22* 23* 24* 25* 26* 27* 28* 29* 30* 31* 32* 33* 34* 35* 36* 37* 38* 39* 40* 41* 42* 43* 44* 45* 46* 47* 48* 49* 50* 51* 52* 53* 54* 55* 56* 57* 58* 59* 60* 61* 62* 63* 64* 65* 66* 67* 68* 69* 70* 71* 72* 73* 74* 75* 76* 77* 78* 79* 80* 81* 82* 83* 84* 85* 86* 87* 88* 89* 90* 91* 92* 93* 94* 95* 96* 97* 98* 99* 100* 101* 102后果展现(递归调用,不好展现每次排序后果) ...

December 28, 2020 · 3 min · jiezi

关于c++:异步方法和TPL-async-await-Parallel

封装咱们要把下面这个Task封装成办法,怎么办? 最重要的一点,这个办法要能返回生成的random,前面的代码要用! public static Task<int> getRandom() { return Task<int>.Run(() => { Thread.Sleep(500); //模仿耗时 return new Random().Next(); }); } @想一想@:应该如何调用这个办法?(_提醒:不要间接__getRandom().Result_) 如果咱们还须要进一步的封装,增加一个办法Process,外面调用getRandom()并把其后果输入: public static void Process() { Task<int> task = getRandom(); Console.WriteLine(task.Result); } 故技重施,如同不行了,这次…… @想一想@:再让Process()返回Task行不行?一个Task套另一Task会呈现什么状况? 在getRandom()和Process()中展现线程Id看一看: Console.WriteLine("in getRandom() with Thread-" + Thread.CurrentThread.ManagedThreadId); 在.NET core的I/O类库中,咱们会发现这样的办法: public static Task AppendAllLinesAsync(string path, IEnumerable<string> contents, Encoding encoding, CancellationToken cancellationToken = default); public static Task<byte[]> ReadAllBytesAsync(string path, CancellationToken cancellationToken = default); 留神: 办法名被增加了Async后缀(举荐命名标准)办法的返回类型为Task或Task<T>异步办法.NET为咱们提供了简洁优雅的异步办法,只须要两个关键字: async 和 await被async标记的办法被称为异步办法, ...

December 26, 2020 · 3 min · jiezi

关于c++:C11拾穗

C++11新关键字alignas:指定对齐大小 alignof:获取对齐大小 decltype auto(从新定义):可作为返回值类型后置时的占位符 static_assert:动态断言 using(从新定义):类型别名或者模板别名 noexcept:申明函数不能够抛出任何异样 export(弃用,不过将来可能留作他用) nullptr constexpr:可在在编译期确认的常量表达式 thread_local:等价于TLS 疾速初始化成员变量C++11中反对应用等号 = 或者花括号 {} 进行就地的(也就是在申明的时候)非动态成员变量初始化。例如: struct init{ int a = 1; double b {1.2};}在C++11规范反对了就地初始化非动态成员的同时,初始化列表这个伎俩也被保留下来了。只不过初始化列表总是看起来“后作用于”非动态成员。 final/override管制C++11提供关键字final,作用是使派生类不可笼罩它所润饰的虚函数。final关键字也可 用于基类中,然而这样定义的虚函数就没有意义了。final通常就是在继承关系的“中途”终止派生类的重载。 在C++中对于基类申明为virtual的函数,之后的重载版本都不须要再申明该重载函数为virtual。即便在派生类中申明了virtual,该关键字也是编译器能够疏忽的。另外,有的虚函数会“跨层”,没有在父类中申明的接口有可能是先人的虚函数接口。所以C\++11引入了虚函数描述符override,来帮忙程序员写继承结构复杂的类型。如果派生类在虚函数申明时应用了override描述符,那么该函数必须重载其基类中的同名函数,否则代码将无奈通过编译。 继承构造函数C++11提供了继承构造函数,在派生类中应用using申明,就能够把基类中的构造函数继承到派生类中。 但其实质是编译器主动生成代码,通过调用父类构造函数来实现,不是真正意义上的“继承”,仅仅是为了缩小代码书写量。 class A { A(int i) {} A(double d, int i) {} A(char *c , double d, int i) {} //... 更多构造函数};class B : A { using A::A; //继承构造函数 //...}委派构造函数C++11提供委派构造函数,能够简化多构造函数的类的编写。如果咱们能将一个构造函数设定为“基准版本”,则其余构造函数能够通过委派“基准版本”来进行初始化。咱们将这个“基准版本”称为指标构造函数。 class Info {public: Info() { InitRest(); }//指标构造函数 Info(int i) : Info() { type = i; }//委派构造函数 Info(char c) : Info() { name = c; }//委派构造函数 private: void InitRest(); { /* 其余初始化 */} int type {1}; char name {'a'}; //...}留神:委派构造函数不能有初始化列表。如果委派构造函数要给变量赋初值,初始化代码必须放在函数体中。 ...

December 23, 2020 · 3 min · jiezi

关于c++:重写QComboBox实现自定义QFontComboBox可以添加自定义字体显示字体样式

在开发的过程中,有个需要,是增加一个字体抉择框,这个简略,我能够间接用了QFontComboBox解决,然而我的需要是字体不必零碎字体,而是用咱们自定义增加的字体库,起初我尝试用QComboBox解决,然而,这个鬼货色却不能独自扭转独自item的字体款式,算了,间接本人写吧,话不多说,上代码: class CFontComboBox : public QComboBox { Q_OBJECTprivate: QListWidget * mFontList;public: CFontComboBox(QWidget * parent = nullptr); void addFont(QString famil); void addFonts(QStringList famils);protected: void wheelEvent(QWheelEvent ) override;};.cpp文件CFontComboBox::CFontComboBox(QWidgetparent) : QComboBox(parent){ mFontList = new QListWidget(this); setModel(mFontList->model()); setView(mFontList); mFontList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setStyleSheet("QComboBox{combobox-popup:0;}"); setMaxVisibleItems(5);}void CFontComboBox::wheelEvent(QWheelEvent * event) {}void CFontComboBox::addFont(QString famil) { auto item = new QListWidgetItem(famil); QFont font; font.setFamily(famil); item->setFont(font); QIcon icon(":icons/T.png"); item->setIcon(icon); mFontList->addItem(item);}void CFontComboBox::addFonts(QStringList famils) { for (auto famil : famils) { addFont(famil); }}功败垂成,话不多说,上图: ...

December 22, 2020 · 1 min · jiezi

关于c++:c重要的概念部分

1. const 润饰指针#include <iostream>using namespace std;int main() { // 1、const 润饰指针 指针常量 int a = 10; int b = 20; int* const p = &a;//指针常量 ==>须要带上& 视为援用值 //特点:指针的指向能够改,指针指向的值不能够改 *p = 200;//正确 //p = 450;// 谬误 cout << *p << endl; // 2、const 润饰指针 常量指针 const int* k = &a; //特点:指针的指向不能够改,指针指向的值能够改 //*k = 900;//谬误 k = &b; cout << *k << endl; return 0;}2.指针和数组#include <iostream>using namespace std;///// <summary>///// 获取数组的长度///// </summary>///// <typeparam name="T"></typeparam>///// <param name="arr"></param>///// <returns></returns>template<class T> int length(T& arr) { int len = sizeof(arr) / sizeof(arr[0]); return len;}int main() { int arr[] = { 37,21,3,49 }; cout << "拜访数组中的第一个元素:" << arr[0] << endl; int* p = arr; cout << "利用拜访数组中的第一个元素:" << *p << endl; ++p; cout << "利用拜访数组中的第二个元素:" << *p << endl; //利用指针循环取值 [原理是指针偏移 第一个地址向后偏移一位 就是向后取值] int* pz = arr; for (int i = 0; i < length(arr); i++) { cout << "利用拜访数组中的第"<<i+1<<"个元素:" << *pz << endl; ++pz; } return 0;}3.值传递和地址传递(相当于java的援用传递)值传递:特点 不扭转原有值 ...

December 21, 2020 · 1 min · jiezi

关于c++:浅谈路径规划

(这里所谈门路布局并不波及机械臂畛域)所谓门路布局,即在地图上找到从A点到B点的可通行路线.这里蕴含两个因素:1、地图;2、“找”--搜索算法.对于地图又蕴含很多,如栅格地图、六边形网格地图、可视图、连通图等,"找"的算法同样也有很多,如迪杰斯特拉算法、A*算法、遗传算法、基于概率RRT、PRM等算法. 地图所谓地图,实质上是一种数据存储构造。该数据结构中存储着哪些坐标可通行,哪些不可通行。目前利用较多的且最直观的莫过于图片(jpg,png等格局),这种存储形式的地图实质上是一种栅格地图,实践上任何一张jpg或png格局的图片都能够作为门路布局中的地图,图片的栅格坐标即可作为地图坐标。事实上,目前大多数钻研门路布局的计划中,都是将其数据转化为栅格图,通过建设栅格图和实在数据之间的关系实现门路的布局。其实,上述中以图片作为地图,这只是一种极为非凡的栅格地图,即四边形栅格。在数据以图片的形式存储过程中,默认不得不以像素坐标存储数据,而当下像素坐标不可避免的须要合乎二维笛卡尔坐标系规定.在这种非凡的四边形栅格坐标示意下,相邻点的坐标只有+1或者-1即可,坐标点之间的间隔天然用欧式间隔示意.诚然,图片形式存储的地图有其得天独厚的劣势:易于了解、直观可视、计算不便,然而这种形式存储的地图构造也有不可避免的毛病...聊完最罕用的四边形栅格地图(其实就是一张图片)外,国外大佬还钻研了六边形栅格地图.相比于四边形栅格地图,六边形栅格地图在并没有那么直观,如果单纯以六边形栅格存储数据,则地图不可视.所以在这篇文章中,作者也只是将四边形网格转化为六边形网格,并提供了坐标转换公式,同时指出了六边形网格各种坐标系之间的优劣,而后进行门路布局.六边形网格地图相比四边形网格地图有肯定的劣势和利用场景,比方在游戏畛域、在军棋推演畛域等.如下两图所示,上图为六边形坐标及其邻域,下图为六边形示意的栅格地图: 从上边两个图中可是看出,六边形网格坐标示意并不是那么易于了解,起码从图上看不是那么直观.在上图中,六边形网格坐标轴的夹角是120度.其实无论四边形还是六边形,在示意地图时,都必须满足一个条件:多边形可能齐全笼罩地图数据.在二维坐标零碎中,目前可能满足此条件的只有正四边形或者正六边形. 门路搜索算法门路搜索算法有很多,这里只谈谈本人对以后路劲钻研现状的了解: 1、对已有优良门路布局算法的改良。在理论利用的过程中,任何一种算法都会面对许多艰难,而在具体利用方向做出针对性的改良,能够疾速无效的晋升算法的性能,同时解决理论问题。 2、混合算法。门路布局的混合算法即各个算法之间的无效联合。任何一个独自的算法,都不足以解决理论问题中的所有门路布局问题,尤其是在针对一些交叉学科中呈现的新问题。发明出新的算法难度大,而门路布局算法之间的优势互补能够无效提供一种解决问题的新思路。一些智能算法如群体智能算法、强化学习算法、模糊控制、神经网络等慢慢引入到门路布局问题中。这种互补式的混合算法促使了各种办法的交融倒退,通过舍短取长,从而产生出一系类更为优良的算法。 3、环境建模技术和门路布局算法的联合。面对简单的二维甚至三维间断动静环境信息时,算法所能做的是无限的,好的建模技术和优良门路布局算法相结合将成为解决这一问题的一种办法。

December 18, 2020 · 1 min · jiezi

关于c++:这才是你需要的CCLinux服务器开发学习路线

C语言和C++属于“造轮子”语言,简直什么都能做。不过一般来说,C语言和C++次要还是做后盾(服务端)开发比拟多,包含: 通信公司后盾开发互联网公司后盾开发游戏公司后盾开发……当然这个后盾开发具体职责又有很多细分,比方: 有做数据处理和剖析的有做根底协定和通信的有做服务端底层利用优化的甚至还有做后盾零碎驱动和内核的…… 从技术学习和理论使用的角度来看,C/C++和Java到底区别在哪?C/C++,它和Java的确不太一样。C语言和C++,尤其C++,语言粒度细、机制多,性能尽管高,但语言自身的包袱也的确重,咱们更违心称它“造轮子”的语言!也正是因为C语言和C++性能好、粒度细,所以什么都能做。而Java自身就是一种服务于互联网软件开发(后端开发+客户端开发)的语言,它有一个显著的“生态圈”的概念,所以应用领域十分清晰。我集体感觉C语言和C++编程比Java还是要难一些,Java毕竟是纯应用层的,C语言和C++则对程序员能力的要求要更高一些。 C/C++的利用方向大多都是后盾或者server开发.,所以我认为必须要学会Linux零碎。不管怎样,上面行将要介绍的这些学习路线和内容实用于以上所有状况。 根底 数据结构与算法 排序与KMP红黑树B树与B+树Hash与布隆过滤器 设计模式 责任链模式过滤器模式公布订阅模式工厂模式代理模式 工程治理 Makefi le/cmake/conf i guregit/svn与继续集成Linux 零碎运行时参数命令 高性能网络设计代码实现 网络io与select/poll/epollreactor的原理与实现http/https web服务器的实现websocket协定与服务器实现 计划剖析服务器百万并发的实现redis/memcached/Nginx网络组件Posix API与网络协议栈UDP可靠性协定 QUIC/KCP 根底组件实现池式组件手写线程池与性能剖析ringbuffer与 内存池实现异步申请池http/mysq1/redis/dnsmysq1连接池的实现redis连接池的实现 高性能组件原子操作CAS音讯队列与无锁实现定时器计划红黑树工夫轮最小堆锁实现原理实现服务器连贯保活设计try/catch组 件的实现 开源组件libevent/libev框架实战异步日志计划log4cpp应用层协定设计ProtoBuf/Thr iftOpenssI对称加密与非对称加密Json数据解析/Xml解析器和工具包字符编码Unicode原理及编程实际 框架协程框架实现NtyCo协程的设计原理与工程案例协程的调度器实现与性能测试 用户态协定栈NtyTCPtcp/ip设计与EpolI的实现tcp/ip定时器与滑动窗口的实现滑动窗口/拥塞慢启动 中间件开发MySQLSQL语句,索引,存储过程,触发器数据库连接池与SQL协定分析存储引擎原理MyISAM与InnoDb本人入手实现一个存储引擎MySQI集群 计划与Rep1 ication原理 RedisRedis相干命令与长久化Redis连接池与协定实现_存储原理与数据模型主从同步与原子模型集群计划主从复制/哨兵/集群 NginxNginx反向代理与零碎参数配置conf原理广告内容推送Nginx过滤模块的实现拜访频率统计Nginx handler模块的实现Nginx http状态机流程过程间通信与Slab共享机制 MongoDB接口编程与文档操作集群计划与长久化备份 dfs内核级反对的分布式存储Ceph分布式小文件存储fastdfs 开源框架Skynet手撕Skynet高性能网关actor实现与cluster集群/负载平衡:skynet网络模块热更新数据共享 ZeroMQZeroMQ Router-Dealer模式实现音讯模型与工程案例网络机制与性能剖析 DPDKPCI原理与testpmd/ 13fwd/skeletonkni数据流程与协定栈解析DNS协定解析与服务器实现高性能Nginx网关实现半虛拟化virtio与vhost减速 Linux内核源码过程治理过程治理和调度锁与过程间通信零碎调用与自定义syscall的实现 内存治理物理内存治理过程虚拟内存mm_ struct剖析我的项目:页面回收和页替换 内存治理物理内存治理过程虚拟内存mm_ struct剖析页面回收和页替换 文件系统虚构文件系统Ext文件系统族无长久存储的文件系统扩大属性和访问控制表 设施驱动内核编译与虚拟机系统升级过程间通信组件实现虚构网络适配器的实现 性能剖析性能工具高性能代码构建零碎tundraHttp压测工具WRK网站压测工具webbench 调试库内存调试性能剖析工具Valgr ind谷歌C++测试框架GoogleTest内存调配跟踪库MemTrack 内核跟踪内核探测SystemTap热图剖析与生成 配套参考书籍材料MySQL:《高性 能MySQL第3版》Nginx:《深 入了解Nginx:模块开发与架构剖析(第2版)》(陶辉)Redis:《Redis 5设计与源码剖析》(陈 雷)Linux内核:《深 入了解Linux内核架构》(郭旭 译)数据结构与算法:《算法导论》 (第3版)性能剖析:《性能之巅 洞悉零碎、企业与云计算》MongoDB:《MongoDB权威 指南》Ceph:《Cep分布式存储学 习指南》(Ceph中 国社区)Docker:《Docker容器 与容器云(第2版)》TCP/IP:《Tcp/Ip详解卷一卷二卷三》Linux零碎编程:《Unix高 级环境编程》计算机:《深刻了解计 算机零碎》ZeroMQ:《ZeroMQ: 云时代极速音讯通信库》DPDK:《深 入浅出DPDK》 ...

December 17, 2020 · 1 min · jiezi

关于c++:wasmer-运行时

上一篇文章分享了基于wasm的openssl实际,讲述了openssl的MD5算法如何在浏览器中执行。在摸索过程中发现了openssl是能够通过wasm编译后间接run,并且有本人的runtime,这是因为openssl.wasm是通过wasmer编译运行的,这一篇文章分享制作具备运行时的openssl.wasm 概述Wasmer介绍Openssl编译到WASM总结一、Wasmer介绍Wasmer是一个用于在服务器上执行WebAssembly的开源运行时。反对基于WebAssembly的超轻量级容器,该容器能够在任何中央运行,还能够嵌入其余编程语言。其生态包含以下几个局部: 1. Wasmer RuntimeWasmer Runtime是Wasmer生态其中一个,容许wasm模块能够独立运行。要害性能是使程序可能以任何编程语言运行;使二进制文件可能在Wasmer反对的任何“操作系统”(例如Linux、macOS、Windows和FreeBSD)上不加批改地运行;充当Wasm模块,通过应用程序二进制接口(ABI),如WASI(WebAssembly System Interface)和Emscripten(1.38.43及更早版本)与本机“操作系统”性能交互的平安桥梁。 2. WAPMWAPM是WebAssembly Package Manager的缩写,为能够独立应用的Wasmer Runtime做的软件包管理器。能够了解为通过Wasmer软件包编译进去的.wasm文件是能够独立运行的,WAPM就是为了治理这些能独立运行的runtime而存在的。如图: 搜寻一个openssl运行时的.wasm。 提供了运行时环境。 整个看上去和docker hub有点像,还有制作方法,咱们能够参考做一个新版的openssl.wasm. 3. WebAssembly.shWebAssembly shell程序是一个在线shell程序,您能够在其中拖放WebAssembly模块以进行尝试,还能够执行WAPM中可用的WASI模块的所有命令。在线演示地址:https://webassembly.sh/ 4. WasienvWasienv是一个工具,旨在将所有编程语言引入WebAssembly WASI的工具能够将不同的编程语言编译到WebAssembly中,而后在浏览器或服务器中运行程序。 看上去和上一篇咱们应用的Emscripten很像,尽管两者都能把高级语言编译成.wasm文件,然而后者更重视web方面的开发在浏览器中运行(也是第一个生成wasm的工具),前者是解决跨平台的问题,体现的是wasm的可移植性。 这里有个WebAssembly WASI的概念,WASI是WebAssembly System Interface的缩写,是WebAssembly 平台的零碎接口, 由Wasmtime我的项目设计,目标是为WASM设计一套引擎无关(engine-indepent), 面向非Web零碎(non-Web system-oriented)的API规范。因为 WebAssembly 是概念机的汇编语言,所以 WebAssembly 须要一个概念操作系统的零碎接口,而不是任何繁多操作系统的零碎接口。 这样,它就能够在所有不同操作系统中运行。 二、 Openssl编译到WASM1. 环境筹备Python 3.7.3Pip3 19.3.1Openssl 官网: https://www.openssl.org/source依赖工具 wasienv2. 装置wasienvcurl https://raw.githubusercontent.com/wasienv/wasienv/master/install.sh | sh问题1我本地无奈解析raw.githubusercontent.com解决办法把install.sh复制到本地执行问题2执行过程中 pip3 install wasienv --install-option="--install-scripts=$INSTALL_DIRECTORY/bin" --upgrade --user 报错,不反对这种写法WARNING: Skipping wasienv as it is not installed./usr/local/lib/python3.7/site-packages/pip/_internal/commands/install.py:235: UserWarning: Disabling all use of wheels due to the use of --build-option / --global-option / --install-option. cmdoptions.check_install_build_global(options)ERROR: Location-changing options found in --install-option: ['--install-scripts'] from command line. This is unsupported, use pip-level options like --user, --prefix, --root, and --target instead.解决办法通过查阅材料,是因为pip3更新到最新版本导致,不反对--install-option=“”显示传参,回退版本pip install --upgrade pip==19.3.1问题3执行过程 curl https://get.wasmer.io -sSfL | sh报错,无奈解析域名解决办法浏览器拜访,把内容复制进去,我保留的文件是install2.sh,批改install.sh中的援用。问题4执行过程 INSTALL_DIRECTORY/bin/wasienv install-sdk unstable File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 659, in urlopenconn = self._get_conn(timeout=pool_timeout) File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 279, in _get_connreturn conn or self._new_conn() File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 948, in _new_conn"Can't connect to HTTPS URL because the SSL module is not available."解决办法剖析 ...

December 17, 2020 · 3 min · jiezi

关于c++:Duilib-打包资源文件到exe

压缩文件增加资源文件virtual LPCTSTR GetResourceID() const{ return MAKEINTRESOURCE(资源ID);};virtual UILIB_RESOURCETYPE GetResourceType() const{ return UILIB_ZIPRESOURCE;};

December 16, 2020 · 1 min · jiezi

关于c++:DuiLib-HandleMessage-HandleCustomMessage-MessageHandler

HandleMessage HandleCustomMessage MessageHandler 三者区别LRESULT CWindowWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam){ return ::CallWindowProc(m_OldWndProc, m_hWnd, uMsg, wParam, lParam);}LRESULT WindowImplBase::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam){ lRes = HandleCustomMessage(uMsg, wParam, lParam, bHandled); if (bHandled) return lRes; if (m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes)) return lRes; return CWindowWnd::HandleMessage(uMsg, wParam, lParam);}//CWindowWnd是父类,WindowImplBase是子类class UILIB_API WindowImplBase : public CWindowWnd如果派生类 如果实现这些虚函数 执行程序如下:HandleMessage --> HandleCustomMessage --> MessageHandler因而只有实现HandleCustomMessage即可

December 16, 2020 · 1 min · jiezi

关于c++:Qt-自定义组件网格组件GirdWidget

自定义组件_滚动横幅&弹窗&对话框&字体图标等自定义组件_圆弧进度条自定义组件_水波进度条自定义组件_多彩仪表盘自定义组件_通用仪表盘自定义组件_网格组件(GirdWidget) 仓库 个性可任意插入、追加 QWidget 类组控件 [举荐QLabel]可自在拖动子组件,并放弃挪动后所有子组件绝对组件地位不变可设置子组件大小、子组件行列间距和子组件与父组件边框的间距可主动依据父组件宽度调整子组件布局可对父组件治理的子组件进行查找、移除等操作子组件原性能不受任何影响,可独自配置后联合父组件实现更丰盛的性能#ifndef GRIDWIDGET_H#define GRIDWIDGET_H#include <QLabel>#include <QMargins>#include <QRect>#include <QVector>/* GridWidget 实现的性能* 1. 可任意插入、追加 QWidget 类组控件 [举荐QLabel]* 2. 可自在拖动子组件,并放弃挪动后所有子绝对组件地位不变* 3. 可设置子组件大小、子组件行列间距和子组件与父组件边框的间距* 4. 可主动依据父组件宽度调整子组件布局* 5. 可对父组件治理的子组件进行查找、移除等操作*//** 阐明:当父组件开始治理子组件时,子组件的生命周期便交由父组件治理,内部不可进行随便 delete 操作* 可应用 removeAt removeOne clear 进行解决* 阐明:子组件原性能不受任何影响,因而可独自配置后联合父组件实现更丰盛的性能*/class GridWidget : public QLabel{ Q_OBJECT Q_PROPERTY(QMargins margins READ margins WRITE setMargins) Q_PROPERTY(QSize size READ size WRITE setSize) Q_PROPERTY(QSize spacing READ spacing WRITE setSpacing)public: explicit GridWidget(QWidget *parent = nullptr); ~GridWidget(); QMargins margins() const; // 返回子组件与父组件间距 QSize size() const; // 返回子组件大小 QSize spacing() const; // 返回子组件间行、列间距 int count() const; // 返回以后父组件中子组件的数量 bool contains(QWidget *widget) const; // 返回以后父组件中是否蕴含此组件 (参数:widget 地址) bool contains(const QString &objectName) const; // 返回以后父组件中是否蕴含此组件 (参数:widget objectName) int indexOf(QWidget* widget, int from = 0) const; // 返回值在父组件中第一次呈现的索引地位,从索引地位向前搜寻 (参数:widget 地址) int indexOf(const QString &objectName, int from = 0) const; // 返回值在父组件中第一次呈现的索引地位,从索引地位向前搜寻 (参数:widget objectName) const QWidget *at(int index) const; // 返回父组件中索引地位i处的项public slots: void append(QWidget* widget); // 将参数组件附加到父组件。 void setSize(QSize size); // 设置子组件大小 void setMargins(QMargins margins); // 设置子组件与父组件的边距 void setSpacing(QSize spaceing); // 设置子组件间的行、列间隔 void setRowSpacing(int spaceing); // 设置子组件的行间距 void setColumnSpacing(int spaceing); // 设置子组件的列间距 void insert(int i, QWidget* widget); // 在指定索引处插入参数组件 QWidget *takeAt(int index); // 删除索引地位i处的子组件并返回它 void removeAt(int index); // 移除指定索引处的子组件 bool removeOne(QWidget *widget); // 移除指定索引处的子组件 (参数:widget 地址) bool removeOne(const QString &objectName); // 移除指定索引处的子组件 (参数:widget objectName) void clear(); // 清空父组件中的所有子组件 void setAnimationEnabled(bool enable); // 设置鼠标点击动画使能protected: bool eventFilter(QObject *object, QEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void resizeEvent(QResizeEvent *event) override; void rearrangeSubWidget();private: QMargins m_margins = {10, 10, 10, 10}; QSize m_size = {60, 60}; QSize m_spacing = {10, 10}; QVector<QWidget*> m_vector; bool m_isAnimation = false; QPoint m_movePos; QPoint m_offsetPos; int m_moveIndex = -1;};#endif // GRIDWIDGET_H

December 15, 2020 · 2 min · jiezi

关于c++:Qt-自定义组件圆弧进度条

自定义组件_滚动横幅&弹窗&对话框&字体图标等自定义组件_圆弧进度条自定义组件_水波进度条自定义组件_多彩仪表盘自定义组件_通用仪表盘 仓库 个性可设置范畴可设置开始旋转角度、完结旋转角度可设置适度动画时常可设置仪表盘题目可设置背景、进度条、值、题目色彩自适应窗体拉伸,文字主动缩放#ifndef ARCPROGRESSBAR_H#define ARCPROGRESSBAR_H#include <QWidget>#include <QColor>#include <QString>#include <QPropertyAnimation>/* 圆弧进度条自定义控件 实现的性能 * 1. 可设置范畴 * 2. 可设置开始旋转角度、完结旋转角度 * 3. 可设置适度动画时常 * 4. 可设置仪表盘题目 * 5. 可设置背景、进度条、值、题目色彩 * 6. 自适应窗体拉伸,文字主动缩放 */class ArcProgressBar : public QWidget{ Q_OBJECT Q_PROPERTY(QColor arcColor READ getArcColor WRITE setArcColor) Q_PROPERTY(QColor baseColor READ getBaseColor WRITE setBaseColor) Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor) Q_PROPERTY(QColor titleColor READ getTitleColor WRITE setTitleColor) Q_PROPERTY(QString title READ getTitle WRITE setTitle) Q_PROPERTY(int minValue READ getMinValue WRITE setMinValue) Q_PROPERTY(int maxValue READ getMaxValue WRITE setMaxValue) Q_PROPERTY(int value READ getValue WRITE setValue) Q_PROPERTY(int animationStepTime READ getAnimationStepTime WRITE setAnimationStepTime) Q_PROPERTY(int startAngle READ getStartAngle WRITE setStartAngle) Q_PROPERTY(int endAngle READ getEndAngle WRITE setEndAngle) Q_PROPERTY(int curValue READ getCurValue WRITE updateValue)public: explicit ArcProgressBar(QWidget *parent = nullptr); ~ArcProgressBar(); QColor getArcColor() const; QColor getBaseColor() const; QColor getTextColor() const; QColor getTitleColor() const; QString getTitle() const; int getMinValue() const; int getMaxValue() const; int getValue() const; int getStartAngle() const; int getEndAngle() const; int getAnimationStepTime() const;public slots: void setArcColor(const QColor &color); // 设置圆弧色彩 void setBaseColor(const QColor &color); // 设置根底色彩 void setTextColor(const QColor &color); // 设置文本色彩 void setTitleColor(const QColor &color); // 设置题目色彩 void setTitle(const QString &title); // 设置Title void setRange(int minValue, int maxValue); // 设置范畴值 void setMinValue(int minValue); // 设置最小值 void setMaxValue(int maxValue); // 设置最大值 void setValue(int value); // 设置目标值 void setAngleRange(int startAngle, int endAngle); // 设施旋转角度范畴 void setStartAngle(int startAngle); // 设置开始旋转角度 void setEndAngle(int endAngle); // 设置完结旋转角度 void setAnimationStepTime(int msec); // 设置每刻度动画持续时间protected: void paintEvent(QPaintEvent *event) override; void drawArc(QPainter *painter); void drawValue(QPainter *painter); void drawTitle(QPainter *painter); void updateValue(int value); int getCurValue() const;signals:private: double m_radius = 0.0; QColor m_arcColor = QColor(34,163,169); QColor m_baseColor = QColor(180,180,180); QColor m_textColor = QColor(34,163,169); QColor m_titleColor = QColor(Qt::black); QString m_title = "正确率"; int m_startAngle = 45; int m_endAngle = 315; int m_maxValue = 100; int m_minValue = 0; int m_curValue = 0; int m_value = 0; QPropertyAnimation m_animation; int m_animationStepTime = 5; QEasingCurve::Type m_easingCurveType = QEasingCurve::Linear;};#endif // ARCPROGRESSBAR_H

December 13, 2020 · 2 min · jiezi

关于c++:Qt-自定义组件水波进度条

自定义组件_滚动横幅&弹窗&对话框&字体图标等自定义组件_圆弧进度条自定义组件_水波进度条自定义组件_多彩仪表盘自定义组件_通用仪表盘 仓库 个性可设置范畴值可设置起始角度可设置水波密度,密度越大浪越大可设置水波高度,高度越大浪越大可设置是否显示进度条可设置是否显示水纹可设置进度色、水纹色、文字色可设置进度条前进方向#ifndef WAREPROGRESSBAR_H#define WAREPROGRESSBAR_H#include <QColor>#include <QString>#include <QTimer>#include <QWidget>/* 多彩仪表盘自定义控件 实现的性能 * 1. 可设置范畴值 * 2. 可设置起始角度 * 3. 可设置水波密度,密度越大浪越大 * 4. 可设置水波高度,高度越大浪越大 * 5. 可设置是否显示进度条 * 6. 可设置是否显示水纹 * 7. 可设置进度色、水纹色、文字色 * 8. 可设置进度条前进方向 */class WareProgressBar : public QWidget{ Q_OBJECT Q_PROPERTY(QColor outerCircleColor READ getPieCircleColor WRITE setPieCircleColor) Q_PROPERTY(QColor waterColor READ getwaterColor WRITE setwaterColor) Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor) Q_PROPERTY(int pieStartAngle READ getPieStartAngle WRITE setPieStartAngle) Q_PROPERTY(int value READ getValue WRITE setValue) Q_PROPERTY(int maxValue READ getMaxValue WRITE setMaxValue) Q_PROPERTY(int minValue READ getMinValue WRITE setMinValue) Q_PROPERTY(int waveDensity READ getWaveDensity WRITE setWaveDensity) Q_PROPERTY(int waveHeight READ getWaveHeight WRITE setWaveHeight) Q_PROPERTY(QString suffixText READ getSuffixText WRITE setSuffixText) Q_PROPERTY(bool waveForwardOrientation READ getWaveIsForwardOrientation WRITE setWaveIsForwardOrientation) Q_PROPERTY(bool waterIsvisible READ getWaterIsvisible WRITE setWaterIsvisible) Q_PROPERTY(bool peiCircleIsvisible READ getPeiCircleIsvisible WRITE setPeiCircleIsvisible) Q_PROPERTY(bool peiForwardOrientation READ getPeiIsForwardOrientation WRITE setPeiIsForwardOrientation)public: explicit WareProgressBar(QWidget *parent = nullptr); ~WareProgressBar(); QColor getPieCircleColor() const; QColor getwaterColor() const; QColor getTextColor() const; int getPieStartAngle() const; int getValue() const; int getMaxValue() const; int getMinValue() const; int getWaveDensity() const; int getWaveHeight() const; QString getSuffixText() const; bool getWaveIsForwardOrientation() const; bool getWaterIsvisible() const; bool getPeiCircleIsvisible() const; bool getPeiIsForwardOrientation() const;public slots: void setPieCircleColor(const QColor &color); // 设置外圆色彩 void setwaterColor(const QColor &color); // 设置水色彩 void setTextColor(const QColor &color); // 设置文本色彩 void setPieStartAngle(int angle); // 设置饼图起始角度 void setValue(int value); // 设置开始值 void setRange(int minValue, int maxValue); // 设置范畴值 void setMaxValue(int value); // 设置最大值 void setMinValue(int value); // 设置最小值 void setWaveDensity(int density); // 设置水波密度 [0 - 10] void setWaveHeight(int height); // 设置水波高度 [0 - 10] void setSuffixText(const QString &text); // 设置提醒文本 void setWaveIsForwardOrientation(bool Orientation); // 设置水波方向 [true 正向; false 反向] void setWaterIsvisible(bool visible); // 设置水是否可见 void setPeiCircleIsvisible(bool visible); // 设置圆饼否可见 void setPeiIsForwardOrientation(bool Orientation); // 设置圆饼前进方向protected: void paintEvent(QPaintEvent *event) override; void drawPieCircel(QPainter *painter); void drawBackground(QPainter *painter); void drawWater(QPainter *painter); void drawText(QPainter *painter);private: double m_radius = 0.0; QColor m_peiCircleColor = QColor(100,184,255); QColor m_waterColor = QColor(100,184,255); QColor m_textColor = QColor(250,250,250); int m_pieStartAngle = 0; int m_value = 0; int m_maxValue = 100; int m_minValue = 0; int m_waveDensity = 1; int m_waveHeight = 5; bool m_waveForwardOrientation = true; QString m_suffixText = "%"; bool m_waterIsvisible = true; bool m_peiCircleIsvisible = true; bool m_peiForwardOrientation = true; double m_offset = 50; QTimer m_timer;};#endif // WAREPROGRESSBAR_H

December 13, 2020 · 2 min · jiezi

关于c++:Qt-自定义组件多彩仪表盘

自定义组件_滚动横幅&弹窗&对话框&字体图标等自定义组件_圆弧进度条自定义组件_水波进度条自定义组件_多彩仪表盘自定义组件_通用仪表盘 仓库 个性可设置范畴值可设置大刻度数量,小刻度数量可设置开始旋转角度、完结旋转角度可设置是否启用动画、动画特效及每刻度动画持续时间可设置外圆背景、内圆背景、提醒指针、刻度尺、刻度值、提醒文字色彩可设置三色刻度占用比例可设置圆环款式,三色圆环、以后圆环可设置指示器款式,球形、指针形、圆角指针、三角形指示器自适应窗体拉伸、刻度尺和文字主动缩放#ifndef COLORDASHBOARD_H#define COLORDASHBOARD_H#include <QColor>#include <QPropertyAnimation>#include <QWidget>/* 多彩仪表盘自定义控件 实现的性能 * 1. 可设置范畴值 * 2. 可设置大刻度数量,小刻度数量 * 3. 可设置开始旋转角度、完结旋转角度 * 4. 可设置是否启用动画、动画特效及每刻度动画持续时间 * 5. 可设置外圆背景、内圆背景、提醒指针、刻度尺、刻度值、提醒文字色彩 * 6. 可设置三色刻度占用比例 * 7. 可设置圆环款式,三色圆环、以后圆环 * 8. 可设置指示器款式,球形、指针形、圆角指针、三角形指示器 * 8. 自适应窗体拉伸、刻度尺和文字主动缩放 */class ColorDashboard : public QWidget{ Q_OBJECT Q_ENUMS(PieStyle) Q_ENUMS(PointerStyle) Q_PROPERTY(int minValue READ getMinValue WRITE setMinValue) Q_PROPERTY(int maxValue READ getMaxValue WRITE setMaxValue) Q_PROPERTY(int scaleMajor READ getScaleMajor WRITE setScaleMajor) Q_PROPERTY(int scaleMinor READ getScaleMinor WRITE setScaleMinor) Q_PROPERTY(int startAngle READ getStartAngle WRITE setStartAngle) Q_PROPERTY(int endAngle READ getEndAngle WRITE setEndAngle) Q_PROPERTY(int animationStepTime READ getAnimationStepTime WRITE setAnimationStepTime) Q_PROPERTY(QColor outerCircleColor READ getOuterCircleColor WRITE setOuterCircleColor) Q_PROPERTY(QColor innerCircleColor READ getInnerCircleColor WRITE setInnerCircleColor) Q_PROPERTY(QColor m_pieColorStart READ getPieStartColor WRITE setPieStartColor) Q_PROPERTY(QColor m_pieColorMid READ getPieMidColor WRITE setPieMidColor) Q_PROPERTY(QColor m_pieColorEnd READ getPieEndColor WRITE setPieEndColor) Q_PROPERTY(QColor scaleColor READ getScaleColor WRITE setScaleColor) Q_PROPERTY(QColor scaleNumColor READ getScaleNumColor WRITE setScaleNumColor) Q_PROPERTY(QColor pointerColor READ getPointerColor WRITE setPointerColor) Q_PROPERTY(QColor centerCirleColor READ getCenterCircleColor WRITE setCenterCircleColor) Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor) Q_PROPERTY(bool isOverlayVisible READ isOverlayVisible WRITE setOverlayVisible) Q_PROPERTY(QColor overlayColor READ getOverlayColor WRITE setOverlayColor) Q_PROPERTY(PieStyle pieStyle READ getPieStyle WRITE setPieStyle) Q_PROPERTY(PointerStyle pointerStyle READ getPointerStyle WRITE setPointerStyle) Q_PROPERTY(QEasingCurve::Type easingCurveType READ getEasingCurve WRITE setEasingCurve) Q_PROPERTY(int curValue READ getCurValue WRITE updateValue)public: enum PieStyle { PieStyle_Three = 0u, // 三色圆环 PieStyle_Current // 以后圆环 }; enum PointerStyle { PointerStyle_Ball = 0u, // 圆指示器 PointerStyle_Indicator, // 指针指示器 PointerStyle_IndicatorR, // 圆角指针指示器 PointerStyle_Triangle // 三角指示器 }; explicit ColorDashboard(QWidget *parent = nullptr); ~ColorDashboard(); int getMinValue() const; int getMaxValue() const; int getValue() const; int getScaleMajor() const; int getScaleMinor() const; int getStartAngle() const; int getEndAngle() const; int getAnimationStepTime() const; QColor getOuterCircleColor() const; QColor getInnerCircleColor() const; QColor getPieStartColor() const; QColor getPieMidColor() const; QColor getPieEndColor() const; QColor getScaleColor() const; QColor getScalCircleColor() const; QColor getScaleNumColor() const; QColor getPointerColor() const; QColor getCenterCircleColor() const; QColor getTextColor() const; bool isOverlayVisible() const; QColor getOverlayColor() const; PieStyle getPieStyle() const; PointerStyle getPointerStyle() const; QEasingCurve::Type getEasingCurve() const;public slots: void setRange(int minValue, int maxValue); // 设置范畴值 void setMinValue(int minValue); // 设置最小值 void setMaxValue(int maxValue); // 设置最大值 void setValue(int value); // 设置目标值 void setScaleMajor(int scaleMajor); // 设置主刻度数量 void setScaleMinor(int scaleMinor); // 设置小刻度数量 void setAngleRange(int startAngle, int endAngle); // 设施旋转角度范畴 void setStartAngle(int startAngle); // 设置开始旋转角度 void setEndAngle(int endAngle); // 设置完结旋转角度 void setAnimationStepTime(int msec); // 设置每刻度动画持续时间 void setOuterCircleColor(const QColor &outerCircleColor); // 设置外圆色彩 void setInnerCircleColor(const QColor &innerCircleColor); // 设置内圆色彩 // 设置饼圆三种色彩 void setPieStartColor(const QColor &scaleStartColor); void setPieMidColor(const QColor &scaleMidColor); void setPieEndColor(const QColor &scaleEndColor); void setScaleColor(const QColor &scaleColor); // 设置刻度色彩 void setScalCircleColor(const QColor &scaleCircleColor); // 设置刻度圆色彩 void setScaleNumColor(const QColor &scaleNumColor); // 设置刻度值色彩 void setPointerColor(const QColor &pointerColor); // 设置指针色彩 void setCenterCircleColor(const QColor &centerCircleColor); // 设置核心圆色彩 void setTextColor(const QColor &textColor); // 设置提醒文本色彩 void setOverlayVisible(bool overlay); // 设置是否显示遮蔽罩 void setOverlayColor(const QColor &overlayColor); // 设置遮蔽罩色彩 void setPieStyle(PieStyle pieStyle); // 设置饼图央视 void setPointerStyle(PointerStyle pointerStyle); // 设置指针款式 void setEasingCurve(QEasingCurve::Type type); // 设置指针动画类型protected: void paintEvent(QPaintEvent *e) override; inline void drawGenericCircle(QPainter *painter, double radius, const QColor &cokor); void drawOuterCircle(QPainter *painter); void drawScaleCircle(QPainter *painter); void drawPieCircle(QPainter *painter); void drawThreePieCircle(QPainter *painter, double radius); void drawCurrentPieCircle(QPainter *painter, double radius); void drawInnerCircle(QPainter *painter); void drawPointerCircle(QPainter *painter); void drawCenterCircel(QPainter *painter); void drawScaleNum(QPainter *painter); void drawScale(QPainter *painter); void drawOverlay(QPainter *painter); void drawPointer(QPainter *painter); void drawPointerBall(QPainter *painter); void drawPointerIndicator(QPainter *painter); void drawPointerIndicatorR(QPainter *painter); void drawPointerTriangle(QPainter *painter); void drawText(QPainter *painter); void updateValue(int value); int getCurValue() const;signals: void valueChanged(int value); void finished();private: double m_radius = 0; // 仪表盘半径 QColor m_outerCircleColor = QColor(80, 80, 80); // 外圆色彩 QColor m_scaleCircleColor = QColor(60, 60, 60); // 刻度圆色彩 QColor m_innerCircleColor = QColor(100, 100, 100); // 内圆色彩 QColor m_centerCirleColor = QColor(250, 250, 250); // 核心圆色彩 QColor m_pointerColor = QColor(223,105,105); // 指针色彩 QColor m_pieColorStart = QColor(24,189,155); // 饼圆开始色彩 QColor m_pieColorMid = QColor(218,218,0); // 饼圆两头色彩 QColor m_pieColorEnd = QColor(255,107,107); // 饼圆完结色彩 QColor m_scaleNumColor = QColor(255,255,255); // 刻度字体色彩 QColor m_scaleColor = QColor(255,255,255); // 刻度色彩 QColor m_overlayColor = QColor(255,255,255); // 遮避罩色彩 QColor m_textColor = QColor(0,0,0); // 提醒文本色彩 PieStyle m_pieStyle = PieStyle_Current; // 饼格调 PointerStyle m_pointerStyle = PointerStyle_Triangle; // 指示器款式 int m_value = 0; // 表盘设定值 int m_curValue = 0; // 表盘以后值 int m_minValue = 0; // 表盘最小值 int m_maxValue = 240; // 表盘最大值 int m_scaleMajor = 10; // 大刻度数量 int m_scaleMinor = 5; // 小刻度数量 【如:总刻度数量 = scaleMajor * scaleMinor】 int m_startAngle = 45; // 起始旋转角度 int m_endAngle = 315; // 完结旋转角度 bool m_isOverlayVisible = true; // 是否显示遮蔽罩 QPropertyAnimation m_animation; // 指针属性动画 int m_animationStepTime = 50; // 每刻度动画持续时间 QEasingCurve::Type m_easingCurveType = QEasingCurve::OutQuad; // 指针动画弛缓曲线类型};#endif // COLORDASHBOARD_H

December 13, 2020 · 4 min · jiezi

关于c++:Qt-自定义组件通用仪表盘

自定义组件_滚动横幅&弹窗&对话框&字体图标等自定义组件_圆弧进度条自定义组件_水波进度条自定义组件_多彩仪表盘自定义组件_通用仪表盘 仓库 个性可设置范畴值可设置大刻度数量,小刻度数量可设置开始旋转角度、完结旋转角度可设置是否启用动画、动画特效及每刻度动画持续时间可设置外圆背景、内圆背景、提醒指针、刻度尺、刻度值、提醒文字色彩可设置三色刻度占用比例自适应窗体拉伸、刻度尺和文字主动缩放#ifndef DASHBOARD_H#define DASHBOARD_H#include <QColor>#include <QEasingCurve>#include <QPropertyAnimation>#include <QString>#include <QWidget>/* 通用仪表盘自定义控件 实现的性能 * 1. 可设置范畴值 * 2. 可设置大刻度数量,小刻度数量 * 3. 可设置开始旋转角度、完结旋转角度 * 4. 可设置是否启用动画、动画特效及每刻度动画持续时间 * 5. 可设置外圆背景、内圆背景、提醒指针、刻度尺、刻度值、提醒文字色彩 * 6. 可设置三色刻度占用比例 * 7. 自适应窗体拉伸、刻度尺和文字主动缩放 */class GenericDashBoard : public QWidget{ Q_OBJECT Q_PROPERTY(int minValue READ getMinValue WRITE setMinValue) Q_PROPERTY(int maxValue READ getMaxValue WRITE setMaxValue) Q_PROPERTY(int value READ getValue WRITE setValue) Q_PROPERTY(int curValue READ getCurValue WRITE updateValue) Q_PROPERTY(int animationStepTime READ getAnimationStepTime WRITE setAnimationStepTime) Q_PROPERTY(int scaleMajor READ getScaleMajor WRITE setScaleMajor) Q_PROPERTY(int scaleMinor READ getScaleMinor WRITE setScaleMinor) Q_PROPERTY(int startAngle READ getStartAngle WRITE setStartAngle) Q_PROPERTY(int endAngle READ getEndAngle WRITE setEndAngle) Q_PROPERTY(int scalePercentage READ getScalePercentage WRITE setScalePercentage) Q_PROPERTY(QColor scaleNumColor READ getScaleNumColor WRITE setScaleNumColor) Q_PROPERTY(QColor outerCircleColor READ getOuterCircleColor WRITE setOuterCircleColor) Q_PROPERTY(QColor innerCircleColor READ getInnerCircleColor WRITE setInnerCircleColor) Q_PROPERTY(QColor scaleStartColor READ getScaleStartColor WRITE setScaleStartColor) Q_PROPERTY(QColor scaleEndColor READ getScaleEndColor WRITE setScaleEndColor) Q_PROPERTY(QColor pointerColor READ getPointerColor WRITE setPointerColor) Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor) Q_PROPERTY(QString suffixText READ getSuffixText WRITE setSuffixText)public: explicit GenericDashBoard(QWidget *parent = nullptr); ~GenericDashBoard(); int getMinValue() const; int getMaxValue() const; int getValue() const; int getAnimationStepTime() const; int getScaleMajor() const; int getScaleMinor() const; int getStartAngle() const; int getEndAngle() const; QColor getScaleNumColor() const; QColor getOuterCircleColor() const; QColor getInnerCircleColor() const; QColor getScaleStartColor() const; QColor getScaleEndColor() const; QColor getPointerColor() const; QColor getTextColor() const; QString getSuffixText() const; QEasingCurve::Type getEasingCurve() const; double getScalePercentage() const;public slots: void setRange(int minValue, int maxValue); // 设置范畴值 void setMinValue(int minValue); // 设置最小值 void setMaxValue(int maxValue); // 设置最大值 void setValue(int value); // 设置目标值 void setAnimationStepTime(int msec); // 设置每刻度动画持续时间 void setScaleMajor(int scaleMajor); // 设置主刻度数量 void setScaleMinor(int scaleMinor); // 设置小刻度数量 void setAngleRange(int startAngle, int endAngle); // 设施旋转角度范畴 void setStartAngle(int startAngle); // 设置开始旋转角度 void setEndAngle(int endAngle); // 设置完结旋转角度 void setScaleNumColor(const QColor &scaleNumColor); // 设置刻度值色彩 void setOuterCircleColor(const QColor &outerCircleColor); // 设置外圆色彩 void setInnerCircleColor(const QColor &innerCircleColor); // 设置内圆色彩 void setScalePercentage(double percentage); // 设置刻度百分比 【对应 m_scaleStartColor m_scaleEndColor】 // 设置刻度两种色彩 void setScaleStartColor(const QColor &scaleStartColor); void setScaleEndColor(const QColor &scaleEndColor); void setPointerColor(const QColor &pointerColor); // 设置指针色彩 void setTextColor(const QColor &textColor); // 设置提醒文本色彩 void setSuffixText(const QString &string); // 设置提醒文字 void setEasingCurve(QEasingCurve::Type type); // 设置指针动画类型protected: void paintEvent(QPaintEvent *event) override; void drawBackground(QPainter *painter); // 绘制背景 void drawScale(QPainter *painter); // 绘制刻度 void drawScaleNum(QPainter *painter); // 绘制刻度值 void drawPainterIndicator(QPainter *painter); // 绘制指示器 void drawText(QPainter *painter); // 绘制提醒文本 int getCurValue() const; void updateValue(int value); // 更新表盘值 【次要在指针动画时应用】signals: void valueChanged(int value); void finished();private: int m_radius = 0; // 仪表盘半径 QColor m_outerCircleColor = QColor(172, 172, 172); // 外圆背景色 【类比于手表金属外框】 QColor m_innerCircleColor = QColor(40, 40, 40); // 内圆背景色 【类比于手表玻璃显示区域】 QColor m_scaleStartColor = QColor(84, 84, 84); // 刻度开始局部色彩 QColor m_scaleEndColor = QColor(Qt::red); // 刻度完结局部色彩 【如:没油、转速等告警提醒】 QColor m_scaleNumColor = QColor(255,255,255); // 刻度值色彩 QColor m_pointerColor = QColor(250, 50, 50); // 指针色彩 QColor m_textColor = QColor(255,255,255); // 提醒文本色彩 int m_curValue = 0; // 表盘指针以后值 【次要在指针动画时应用】 int m_value = 0; // 表盘指针最终指向的值 int m_minValue = 0; // 表盘最小值 int m_maxValue = 240; // 表盘最大值 int m_startAngle = 45; // 刻度盘起始角度 int m_endAngle = 315; // 刻度盘完结角度 int m_scaleMajor = 10; // 大刻度数量 int m_scaleMinor = 5; // 小刻度数量 【如:总刻度数量 = scaleMajor * scaleMinor】 double m_scalePercentage = 0.8; // 表盘刻度划分百分比 【对应 m_scaleStartColor m_scaleEndColor】 QString m_suffixText = "Km/h"; // 提醒文本后缀 【如:Km/h 等】 QPropertyAnimation m_animation; // 指针属性动画 int m_animationStepTime = 50; // 每刻度动画持续时间 QEasingCurve::Type m_easingCurveType = QEasingCurve::OutQuad; // 指针动画弛缓曲线类型};#endif // DASHBOARD_H

December 13, 2020 · 3 min · jiezi

关于c++:C服务编译耗时优化原理及实践

一、背景大型C++工程项目,都会面临编译耗时较长的问题。不论是开发调试迭代、准入测试,亦或是继续集成阶段,编译行为无处不在,升高编译工夫对进步研发效率来说具备十分重要意义。 美团搜寻与NLP部为公司提供根底的搜寻平台服务,出于性能的思考,底层的根底服务通过C++语言实现,其中咱们负责的深度查问了解服务(DeepQueryUnderstanding,下文简称DQU)也面临着编译耗时较长这个问题,整个服务代码在优化前编译工夫须要二十分钟左右(32核机器并行编译),曾经影响到了团队开发迭代的效率。基于这样的背景,咱们针对DQU服务的编译问题进行了专项优化。在这个过程中,咱们也积攒了一些优化的常识和教训,在这里分享给大家。 二、编译原理及剖析2.1 编译原理介绍为了更好地了解编译优化计划,在介绍优化计划之前,咱们先简略介绍一下编译原理,通常咱们在进行C++开发时,编译的过程次要蕴含上面四个步骤: 预处理器:宏定义替换,头文件开展,条件编译开展,删除正文。 gcc -E选项能够失去预处理后的后果,扩大名为.i 或 .ii。C/C++预处理不做任何语法查看,不仅是因为它不具备语法查看性能,也因为预处理命令不属于C/C++语句(这也是定义宏时不要加分号的起因),语法查看是编译器要做的事件。预处理之后,失去的仅仅是真正的源代码。编译器:生成汇编代码,失去汇编语言程序(把高级语言翻译为机器语言),该种语言程序中的每条语句都以一种规范的文本格式确切的形容了一条低级机器语言指令。 gcc -S选项能够失去编译后的汇编代码文件,扩大名为.s。汇编语言为不同高级语言的不同编译器提供了通用的输入语言。汇编器:生成指标文件。 gcc -c选项能够失去汇编后的后果文件,扩大名为.o。.o文件,是依照的二进制编码方式生成的文件。链接器:生成可执行文件或库文件。 动态库:指编译链接时,把库文件的代码全副退出到可执行文件中,因而生成的文件比拟大,但在运行时也就不再须要库文件了,其后缀名个别为“.a”。动静库:在编译链接时并没有把库文件的代码退出到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可执行文件比拟小,动静库个别后缀名为“.so”。可执行文件:将所有的二进制文件链接起来交融成一个可执行程序,不论这些文件是指标二进制文件还是库二进制文件。2.2 C++编译特点(1)每个源文件独立编译 C/C++的编译系统和其余高级语言存在很大的差别,其余高级语言中,编译单元是整个Module,即Module下所有源码,会在同一个编译工作中执行。而在C/C++中,编译单元是以文件为单位。每个.c/.cc/.cxx/.cpp源文件是一个独立的编译单元,导致编译优化时只能基于本文件内容进行优化,很难跨编译单元提供代码优化。 (2)每个编译单元,都须要独立解析所有蕴含的头文件 如果N个源文件援用到了同一个头文件,则这个头文件须要解析N次(对于Thrift文件或者Boost头文件这类动辄几千上万行的头文件来说,几乎就是“鬼故事”)。 如果头文件中有模板(STL/Boost),则该模板在每个cpp文件中应用时都会做一次实例化,N个源文件中的std::vector<int>会实例化N次。 (3)模板函数实例化 在C++ 98语言规范中,对于源代码中呈现的每一处模板实例化,编译器都须要去做实例化的工作;而在链接时,链接器还须要移除反复的实例化代码。显然编译器遇到一个模板定义时,每次都去进行反复的实例化工作,进行反复的编译工作。此时,如果可能让编译器防止此类反复的实例化工作,那么能够大大提高编译器的工作效率。在C++ 0x规范中一个新的语言个性 -- 内部模板的引入解决了这个问题。 在C++ 98中,曾经有一个叫做显式实例化(Explicit Instantiation)的语言个性,它的目标是批示编译器立刻进行模板实例化操作(即强制实例化)。而内部模板语法就是在显式实例化指令的语法根底上进行批改失去的,通过在显式实例化指令前增加前缀extern,从而失去内部模板的语法。 ① 显式实例化语法:template class vector<MyClass>。② 内部模板语法:extern template class vector<MyClass>。 一旦在一个编译单元中应用了内部模板申明,那么编译器在编译该编译单元时,会跳过与该内部模板申明匹配的模板实例化。 (4)虚函数 编译器解决虚函数的办法是:给每个对象增加一个指针,寄存了指向虚函数表的地址,虚函数表存储了该类(包含继承自基类)的虚函数地址。如果派生类重写了虚函数的新定义,该虚函数表将保留新函数的地址,如果派生类没有从新定义虚函数,该虚函数表将保留函数原始版本的地址。如果派生类定义了新的虚函数,则该函数的地址将被增加到虚函数表中。 调用虚函数时,程序将查看存储在对象中的虚函数表地址,转向相应的虚函数表,应用类申明中定义的第几个虚函数,程序就应用数组的第几个函数地址,并执行该函数。 应用虚函数后的变动: ① 对象将减少一个存储地址的空间(32位零碎为4字节,64位为8字节)。② 每个类编译器都创立一个虚函数地址表。③ 对每个函数调用都须要减少在表中查找地址的操作。 (5)编译优化 GCC提供了为了满足用户不同水平的的优化须要,提供了近百种优化选项,用来对编译工夫,指标文件长度,执行效率这个三维模型进行不同的取舍和均衡。优化的办法不一而足,总体上将有以下几类: ① 精简操作指令。② 尽量满足CPU的流水操作。③ 通过对程序行为地猜想,从新调整代码的执行程序。④ 充沛应用寄存器。⑤ 对简略的调用进行开展等等。 如果全副理解这些编译选项,对代码针对性的优化还是一项简单的工作,侥幸的是GCC提供了从O0-O3以及Os这几种不同的优化级别供大家抉择,在这些选项中,蕴含了大部分无效的编译优化选项,并且能够在这个根底上,对某些选项进行屏蔽或增加,从而大大降低了应用的难度。 O0:不做任何优化,这是默认的编译选项。O和O1:对程序做局部编译优化,编译器会尝试减小生成代码的尺寸,以及缩短执行工夫,但并不执行须要占用大量编译工夫的优化。O2:是比O1更高级的选项,进行更多的优化。GCC将执行简直所有的不蕴含工夫和空间折中的优化。当设置O2选项时,编译器并不进行循环展开以及函数内联优化。与O1比较而言,O2优化减少了编译工夫的根底上,进步了生成代码的执行效率。O3:在O2的根底上进行更多的优化,例如应用伪寄存器网络,一般函数的内联,以及针对循环的更多优化。Os:次要是对代码大小的优化, 通常各种优化都会打乱程序的构造,让调试工作变得无从着手。并且会打乱执行程序,依赖内存操作程序的程序须要做相干解决能力确保程序的正确性。编译优化有可能带来的问题: ① 调试问题:正如下面所提到的,任何级别的优化都将带来代码构造的扭转。例如:对分支的合并和打消,对专用子表达式的打消,对循环内load/store操作的替换和更改等,都将会使指标代码的执行程序变得面目全非,导致调试信息严重不足。 ② 内存操作程序扭转问题:在O2优化后,编译器会对影响内存操作的执行程序。例如:-fschedule-insns容许数据处理时先实现其余的指令;-fforce-mem有可能导致内存与寄存器之间的数据产生相似脏数据的不统一等。对于某些依赖内存操作程序而进行的逻辑,须要做严格的解决后能力进行优化。例如,采纳Volatile关键字限度变量的操作形式,或者利用Barrier迫使CPU严格依照指令序执行。 (6)C/C++ 跨编译单元的优化只能交给链接器 当链接器进行链接的时候,首先决定各个指标文件在最终可执行文件里的地位。而后拜访所有指标文件的地址重定义表,对其中记录的地址进行重定向(加上一个偏移量,即该编译单元在可执行文件上的起始地址)。而后遍历所有指标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的地位上填写实现地址,最初把所有的指标文件的内容写在各自的地位上,就生成一个可执行文件。链接的细节比较复杂,链接阶段是单过程,无奈并行减速,导致大我的项目链接极慢。 三、服务问题剖析DQU是美团搜寻应用的查问了解平台,外部蕴含了大量的模型、词表、在代码构造上,蕴含20多个Thrift文件 ,应用大量Boost处理函数 ,同时引入了SF框架,公司第三方组件SDK以及分词三个Submodule,各个模块采纳动静库编译加载的形式,模块之间通过音讯总线做数据的传输,音讯总线是一个大的Event类,这样这个类就蕴含了各个模块须要的数据类型的定义,所以各个模块都会引入Event头文件,不合理的依赖关系造成这个文件被改变,简直所有的模块都会从新编译。 ...

December 11, 2020 · 2 min · jiezi

关于c++:WonderTrader发布v053版本

明天(2020年12月8日)WonderTrader公布了v0.5.3版本,wtpy的也同步公布了v0.5.3.0版本。上次公布版本的工夫是9月21日,差不多过来了两个半月了。最近WonderTrader在一些敌人的举荐下,缓缓有了更多关注的人,甚至有一个敌人筹备成为咱们本人团队之外第一个吃螃蟹上实盘的人。在此我示意深深的感激,也心愿有更多的人能关注WonderTrader,应用WonderTrader,促成WonderTrader的提高和欠缺。这次公布新版本的内容和上次打算的出入很大,次要集中在问题的修复和细节的欠缺。因为笔者工作太忙,有点顾不上功能性改良,请大家多多见谅。这次更新中有两个比拟重要的点:首先是回测退出了滑点的设置,能够依据须要设置固定跳数的滑点;其次是因为有敌人要在linux上实盘,所以针对linux重复批改了很多之前没有留神到的问题,为linux上实盘发明了更好的条件。 WonderTrader在v0.5.3中做了如下批改:回测引擎减少了设置成交滑点的参数选项,不设置则为0修改了C++ demo中的一些代码的细节问题执行模块为搭建分布式执行框架做了一些事后调整ParserUDP模块接管缓存改成8M减少了一个MiniLoader工程,用于从CTPMini2接口拉取合约列表将linux下编译的boost依赖从动静库改成动态库其余细节欠缺wtpy在v0.5.3.0中做了如下批改:CTPLoader减少一个isMini的参数,用于管制底层调用MiniLoader对接CTPMini2进行拉取WtKlineData新增一个slice办法,用于对已有K线进行切片C++底层更新到2020/12/08公布的v0.5.3版本CtaContext新增一个stra_get_sessinfo接口,用于获取种类的交易工夫信息monitor模块中的web-gui批改了一些bug修改了绩效剖析模块的一些bug下一个阶段的打算(和上次发版本的打算一样,因为都没有推动,囧)持续欠缺文档公布更多的策略利用的公众号文章近程控制台集成更多功能(主动部署、在线回测)提供更多易用性方面的改良外围性能测试优化结束语WonderTrader在Linux平台下的编译,之前笔者只在Ubuntu上进行了开发环境的搭建和编译。前段时间在一些用户的要求下,笔者有针对CentOS7和CentOS8进行了开发环境的搭建和测试。同时有用户反馈之前linux上链接的boost库是动静库,如果部署的指标机器没有装置boost库,就会启动失败。所以从v0.5.3开始,依赖的boost全副采纳动态编译的形式,预编译成.a文件,供WonderTrader编译调用。最初,WonderTrader编译所须要的依赖库,笔者曾经共享在百度网盘中了,有须要的用户能够自取。链接:https://pan.baidu.com/s/1Bdxh... 提取码:d6bh

December 8, 2020 · 1 min · jiezi

关于c++:C实现的高效简便易用的Tuliplog日志库边学边用

日期作者版本备注2020-12-6dingbinv1.0 Tulip-log日志库简介Tulip-log是作者开源的用C++语言实现的一个稳固高效的日志库。Github地址是:https://github.com/apollo008/...。它不依赖与任何第三方库,次要利用于类Unix操作系统下。它具备以下劣势: 性能稳固,代码精炼,无任何第三方依赖,运行效率高;兼顾个别惯例的log配置文件选项,比方Java编写的log4j的配置格局,上手容易;反对多线程同步疾速输入日志;反对多种日志输入形式,目前反对的有Console、File和Udp转发日志;对最罕用的输入日志到文件的形式,反对文件名滚动和较多丰盛细节个性定义;宏定义形式极大简化了日志接口应用,编写打印日志代码简要便当。应用办法应用办法可参考examples/hello_tulip.cpp代码示例: #include "tulip/TLogDefine.h"int main(int argc, char** argv) { //configurate TLog from logger config file 'logger.conf' TLOG_CONFIG("logger.conf"); //declare and setup tlog variable TLOG_DECLARE_AND_SETUP_LOGGER(HELLOTULIP, MAIN); for (uint32_t i = 0; i < 100; ++i) { //output log by convenient micro definitions TLOG_LOG(INFO,"the values is:[%u].", i); sleep(1); } //flush before shutdown TLog TLOG_LOG_FLUSH(); //at last shutdown TLog TLOG_LOG_SHUTDOWN(); return 0;}这里给出一个Tulip log的配置文件logger.conf内容可供参考: #Tulip log配置文件tlog.rootLogger=INFO, tulipAppender,consoleAppendertlog.appender.tulipAppender=FileAppendertlog.appender.tulipAppender.max_file_size=3024tlog.appender.tulipAppender.fileName=logs/app.logtlog.appender.tulipAppender.flush=falsetlog.appender.tulipAppender.delay_time=1tlog.appender.tulipAppender.layout=PatternLayouttlog.appender.tulipAppender.layout.LogPattern=[%%d] [%%t,%%F:%%n -- %%f() %%l] [%%m]tlog.appender.consoleAppender=ConsoleAppendertlog.appender.consoleAppender.delay_time=1tlog.appender.consoleAppender.layout=PatternLayouttlog.appender.consoleAppender.layout.LogPattern=[%%d] [%%t,%%F:%%n -- %%f() %%l] [%%m]tlog.appender.udpAppender=UdpAppendertlog.appender.udpAppender.ip=192.168.0.211tlog.appender.udpAppender.port=14878tlog.appender.udpAppender.layout=PatternLayouttlog.appender.udpAppender.layout.LogPattern=[%%d] [%%t,%%F:%%n -- %%f() %%l] [%%m]####################################################################编译和装置目前反对类Unix环境下编译装置,办法如下: ...

December 6, 2020 · 1 min · jiezi

关于c++:C可变参数函数实现方法

C++可变参数函数实现办法C++编程中实现可变参数函数有多种路径,本文介绍一种最常见的实现路径,即可变参数宏办法:形参生命为省略符,函数实现时用参数列表宏拜访参数。 1. 可变参数宏实现变参函数可变参数宏实现可分为以下几个步骤: 函数形参原型中给出省略符;函数实现中申明一个va_list可变参数列表变量;开始初始化结构va_list变量;拜访变参列表;实现清理工作;上述步骤的实现须要应用到四个宏: va_listvoid va_start(va_list ap, last_arg)type va_arg (va_list ap, type)void va_end(va_list ap)va_list 是在C语言中解决变参问题的一组宏void va_start(va_list ap, last_arg)ap :是一个 va_list 类型的对象,它用来存储通过 va_arg 获取额定参数时所必须的信息。last_arg :是最初一个传递给函数的已知的固定参数,即省略号之前的参数。宏定义:type va_arg (va_list ap, type)该宏用于变参数函数调用过程中,type是以后参数类型,调用该宏后,ap指向变参数列表中的下一个参数,返回ap指向的参数值,是一个类型为type的表达式。 ap是arg_ptr参数指针之意。void va_end(va_list ap)容许应用了 va_start 宏的带有可变参数的函数返回。如果在从函数返回之前没有调用 va_end,则后果为未定义。这些宏在头文件stdarg.h中申明定义。因而应用时须要蕴含该头文件。 上面给出用法示例: #include <stdarg.h>//可变参数函数sum(),求任意个数整数的和。//Step1: 函数形参原型中给出省略符int Sum(int count, ...);int Sum(int count, ...) { //Step2: 函数实现中申明一个va_list可变参数列表变量; va_list ap; //Step3: 开始初始化结构va_list变量, 第二个参数为最初一个确定的形参 va_start(ap, count); int sum = 0; for(int i = 0; i < count; i++) { //读取可变参数,的二个参数为可变参数的类型 sum += va_arg(ap, int); } //清理工作 va_end(ap); return sum;}理论中应用可变参数宏实现C++可变参数函数编程,还要留神一下几点: ...

December 5, 2020 · 1 min · jiezi

关于c++:Qt基于TCP的网络聊天室

仓库 整顿自狄泰软件学院外传篇

December 4, 2020 · 1 min · jiezi

关于c++:dd

include<iostream>include<cctype>using namespace std; int main(){ char n;while (cin >> n){ if (isalpha(n)) cout << "YES"; else cout << "NO";}}

December 4, 2020 · 1 min · jiezi

关于c++:20201204tmp记录

/*KiKi想晓得他的考试分数是否通过,请帮他判断。从键盘任意输出一个整数示意的分数,编程判断该分数是否在及格范畴内,如果及格,即:分数大于等于60分,是输入“Pass”,否则,输入“Fail”。https://www.nowcoder.com/prac...BC43*/ include<iostream>using namespace std; int main(){ int n;while (cin>>n){ if (n >= 60) cout << "Pass" << endl; else cout << "Fail" << endl;}}

December 4, 2020 · 1 min · jiezi

关于c++:C中STL中sort算法使用了什么排序算法

STL所提供的各式各样的算法中,sort()是最简单宏大的一个。这个算法承受两个RandomAccessIterators(随机存取迭代器),而后将区间内的所有元素以渐增形式由小到大重新排列。第二个版本则容许用户指定一个仿函数(functor),作为排序规范。STL的所有关系型容器(associative containers)都有用主动排序功能(底层构造采纳RB-tree),所以不须要用到这个sort算法。至于序列式容器(sequence containers)中的stack、queue和priority-queue都有特地的出入口,不容许用户对元素排序。剩下vector、deque和list,前两者的迭代器属于RandomAccessIterators,适宜应用sort算法,list的迭代器则属于BidirectioinalIterators,不在STL规范之列的slist,其迭代器更属于ForwardIterator,都不适宜应用sort算法。如果要对list或slist排序,应该应用它们本人提供的member functions sort()。STL的sort算法,数据量大时采纳Quick Sort,分段递归排序。一旦分段后的数据量小于某个门槛,为防止Quick Sort的递归调用带来过大的额定负荷(overhead),就改用Insertion Sort。如果递归档次过深,还回改用Heap Sort。 --摘自《STL源码分析》即STL中的sort算法是快排、插入排序和堆排序的综合。

November 30, 2020 · 1 min · jiezi

关于c++:数据结构与算法入门指南-排序

数据结构与算法入门指南理解各个排序的算法原理比拟适宜找工作面试的时候用,在刷题比赛的时候间接应用sort函数即可sort函数sort作为C++自带的函数,应用频率比拟高,个别遇到须要排序的数组用就行了,能解决大部分须要排序的问题。上面演示一下各种用法。 根底用法最根底的用法,对数组间接排序(默认从小到大排序)。 int A[10] = { 5,4,8,7,6,4,1,6,5,1 };sort(A, A + 10); // A = { 1,1,4,4,5,5,6,6,7,8 }sort函数的前两个参数为首地址与尾地址,示意须要排序一段数组。在上例中,A有10个元素,而应用A时会返回A的首地址,A + 10示意在首地址上向后偏移10个地位后的地址,用(A,A + 10)能够示意A[0 ~ 9]。 如果只想对前五位排序,也能够这样写sort(A, A + 5)。 对于STL中的vector也是如此,应用对象中的begin()与end()获取首地址与尾地址。 vector<int> A = { 5,4,6,8,7,4,1,6,9 };sort(A.begin(), A.end()); // A = { 1,4,4,5,6,6,7,8,9 }那么对于自定义的构造体呢?看上面。 自定义排序用法sort函数还有第三个可选参数,就是自定义排序的办法,传入办法名或者匿名函数即可。传入的办法的参数必须是两个同类型的且返回值为bool类型。 如果不应用第三个参数,sort函数会默认调用对象的<办法来比拟两个对象的大小关系,应用构造体时须要重写一下operator<。 应用匿名函数 int A[10] = { 5,1,7,9,5,4,8,3,1,0 };sort(A, A + 10, [](int a, int b) { return a > b; }); //从大到小排序//A = { 9,8,7,5,5,4,3,1,1,0 }应用办法 ...

November 30, 2020 · 3 min · jiezi

关于c++:还搞不懂C语言中的函数指针看完你就明白了

1.函数指针的定义 顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子: A) char * (*fun1)(char * p1,char * p2);B) char * *fun2(char * p1,char * p2);C) char * fun3(char * p1,char * p2); 看看下面三个表达式别离是什么意思? C)这很容易,fun3是函数名,p1,p2是参数,其类型为char 型,函数的返回值为char 类型。B) 也很简略,与C)表达式相比,惟一不同的就是函数的返回值类型为char**,是个二级指针。A) fun1是函数名吗?回顾一下后面解说数组指针时的情景。咱们说数组指针这么定义或者更清晰: int (*)[10] p; 再看看A)表达式与这里何其相似!明确了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,咱们把这个表达式改写一下: char * (*)(char * p1,char * p2) fun1; 这样子是不是难看一些呢?只惋惜编译器不这么想。^_^。 2.函数指针应用的例子 下面咱们定义了一个函数指针,但如何来应用它呢?先看如下例子: #include <stdio.h>#include <string.h>char * fun(char * p1,char * p2){ int i = 0; i = strcmp(p1,p2); if (0 == i) { return p1; } else { return p2; }}int main(){ char * (*pf)(char * p1,char * p2); pf = &fun; (*pf) ("aa","bb"); return 0;} 这里须要留神到是,在Visual C++6.0里,给函数指针赋值时,能够用&fun或间接用函数名fun。这是因为函数名被编译之后其实就是一个地址,所以这里两种用法没有实质的差异。这个例子很简略,就不再具体探讨了。 咱们应用指针的时候,须要通过钥匙(“”)来取其指向的内存外面的值,函数指针应用也如此。通过用(pf)取出存在这个地址上的函数,而后调用它。 3.(int)&p ----这是什么? 兴许下面的例子过于简略,咱们看看上面的例子: ...

November 28, 2020 · 1 min · jiezi

关于c++:算法题的准备

逆置程序表 void Reverse(Seqlist,int left,int right){int k = left , j = right;DataType temp;while(k<j){temp = L.data[k],L.Data[k]=L.data[j],L.Data[k]=tem;k++,j--;}}//工夫复杂度O(n);走迷宫问题: #include <cstring>#include <iostream>#include <algorithm>#include <queue>using namespace std;typedef pair<int, int> PII;const int N = 110;int n, m;int g[N][N], d[N][N];int bfs(){ queue<PII> q; memset(d, -1, sizeof d); d[0][0] = 0; q.push({0, 0}); int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};//联合起来别离对应上下左右 while (q.size()) { auto t = q.front();//宽搜罕用,队列后取数 q.pop();//当你看这段代码没有达到很透彻的时候倡议不要跳过 ,认真思考 for (int i = 0; i < 4; i ++ ) { int x = t.first + dx[i], y = t.second + dy[i];//别离对应指标点像上下左右做试探,而后对二维上下左右做取值 if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1) {//如果x,y在符合条件范畴之内 且没有被摸索过 并且路是通的, d[x][y] = d[t.first][t.second] + 1; q.push({x, y}); } } }//这里为什么是[n-1][m-1] return d[n - 1][m - 1];}int main(){ cin >> n >> m; for (int i = 0; i < n; i ++ ) for (int j = 0; j < m; j ++ ) cin >> g[i][j]; cout << bfs() << endl; return 0;}

November 27, 2020 · 1 min · jiezi

关于c++:Xrepo一个现代化的跨平台-CC-包管理器

xrepo 是一个基于 Xmake 的跨平台 C/C++ 包管理器。 我的项目源码官网文档它基于 xmake 提供的运行时,但却是一个残缺独立的包管理程序,相比 vcpkg/homebrew 此类包管理器,xrepo 可能同时提供更多平台和架构的 C/C++ 包。 并且还反对多版本语义抉择,另外它还是一个去中心化的分布式仓库,不仅仅提供了官网的 xmake-repo 仓库,还反对用户自建多个公有仓库。 同时,xrepo 也反对从 vcpkg/homebrew/conan 等第三方包管理器中安装包,并提供对立统一的库链接信息,不便与第三方我的项目的集成对接。 如果你想要理解更多,请参考:在线文档, Github 以及 Gitee 装置咱们只须要装置上 xmake 就能够应用 xrepo 命令,对于 xmake 的装置,咱们能够看下:xmake 装置文档。 反对平台Windows (x86, x64)macOS (i386, x86_64, arm64)Linux (i386, x86_64, cross-toolchains ..)*BSD (i386, x86_64)Android (x86, x86_64, armeabi, armeabi-v7a, arm64-v8a)iOS (armv7, armv7s, arm64, i386, x86_64)MSYS (i386, x86_64)MinGW (i386, x86_64, arm, arm64)Cross Toolchains反对的包治理仓库官网自建仓库 xmake-repo (tbox >1.6.1)用户自建仓库Conan (conan::openssl/1.1.1g)Vcpkg (vcpkg:ffmpeg)Homebrew/Linuxbrew (brew::pcre2/libpcre2-8)Pacman on archlinux/msys2 (pacman::libcurl)Clib (clib::clibs/bytes@0.0.4)Dub (dub::log 0.4.3)分布式仓库反对除了能够间接从官网仓库:xmake-repo 检索安装包之外,咱们还能够增加任意多个自建的仓库,甚至能够齐全隔离外网,仅仅在公司外部网络保护公有包的装置集成。 ...

November 25, 2020 · 3 min · jiezi

关于c++:不要假装努力了你真的会学习吗

学什么 根底与利用广度与深度哲学英语怎么学 常识体系克服忘记碎片工夫 用起来技术分享造个轮子咱们置信努力学习肯定会有播种,然而办法不当,既让人身心疲乏,也没有切实的回报。高中时代,我的同桌是个丑陋女同学。她的物理问题很差,尽管她十分怠惰的学习,但问题总是不现实。为了坚固纯净的同学关系,我亲密无间地辅导她的物理,发现她不晓得题目考什么。咱们的教科书与试题都围绕着考试纲要开展,看到一道题,应该先想想它在考哪些定理和公式的使用。不少敌人每天都浏览技术文章,然而第二天就忘洁净了。工作中领导和共事都认可你的沟通和技术能力,然而跳槽面试却每每碰壁。面试官问技术计划,明明心里分明,用嘴说进去却前言不搭后语。面试官再问底层算法,你说看过然而遗记了。他不在乎你看没看过,答不上就是零分。正如男女相亲,男方谈吐洒脱能力吸引姑娘。可是男方缓和了,平时挺能说,要害时候却支支吾吾,姑娘必然认为他不行。人生充斥了许多考试,无形的和有形的,每次考试的机会只有一次。工作五年十年后,他人成了架构师,本人还在基层打滚,起因是什么?职场上无奈胜利升迁的起因有很多,没有继续学习、学习效果不好、无奈通过心仪公司的的面试,肯定是很重要的起因。把本人当成一台计算机,既有输出,也要有输入,用输入倒逼输出。 学什么根底与利用近些年诞生了许多新技术,比方最时尚的AI(目前还在智障阶段),数学根底是初中就接触过的概率统计。万丈高楼从地起,不要被新工具或者中间件迷住双眼,一味地追新求快。基础知识是所有技术的基石,在将来很长的工夫都不会变动,应该破费足够的工夫坚固根底。以数据结构和算法为例,大家浏览一下Java的BitSet的源码,外面有大量的移位操作,移位运算把握的好,看这份源码就没问题。Java同步工具类AQS用到了双向链表,链表常识不过关,必定搞不懂它的原理。互联网大厂都喜爱考算法,为了通过面试也要精通算法。以Java工程师应该把握的常识为例,按重要水平排出六个梯度: 第一梯度:计算机组成原理、数据结构和算法、网络通信原理、操作系统原理;第二梯度:Java根底、JVM内存模型和GC算法、JVM性能调优、JDK工具、设计模式;第三梯度:Spring系列、Mybatis、Dubbo等支流框架的使用和原理;第四梯度:MySQL(含SQL编程)、Redis、RabbitMQ/RocketMQ/Kafka、ZooKeeper等数据库或者中间件的使用和原理;第五梯度:CAP实践、BASE实践、Paxos和Raft算法等其余分布式实践;第六梯度:容器化、大数据、AI、区块链等等前沿技术实践;有同学认为第五梯度应该在移到第一梯度。其实很多小公司的日活犹如古天乐一样平平无奇,离大型分布式架构还远得很。学习框架和中间件的时候,棘手把握分布式实践,成果更好。 广度与深度许多公司的招聘JD没有设定技术人员年龄门槛,然而会加上一句“具备与年龄相当的常识的广度与深度”。多广才算广,多深才算深?这是很主观的话题,这里不展开讨论。如何变得更广更深呢?冲破支出回升的瓶颈,挖掘本人真正的趣味。大多数人只是公司的一般职员,支出回升的瓶颈就是升职加薪。许多IT公司会对技术人员有个评级,如果你的评级不高,那就按照升级章程致力降级。如果你在一个小公司,支出个别,发展前景不明,筹备大厂的面试就是最好的学习过程。在这些过程中,你必然学习更多常识,变得更广更深。个人兴趣是后退的能源之一,许多出名开源我的项目都源于作者的趣味。个人兴趣并不局限技术畛域,能够是其余学科。我有个敌人喜爱玩山地自行车,还给一些做自行车话题的自媒体投稿。长此以往,竟然可能写一手好文章了,我置信他也能写好技术文档。 哲学哲学不是故作高深的学科,它的现实意义就是解决问题。年老小伙是怎么泡妞的?三天两头花一直,大庭广众跪求爱。这类套路为什么总是能胜利呢?礼物满足女人的物欲,当众求爱满足女人的虚荣心,投其所好。食堂大妈打菜的手越来越抖,辣子鸡丁变成辣子辣丁,为什么呢?食堂要管制老本,间接提价会惹众怒。迷信上的哲学,个别指钻研事物倒退的法则,演绎终极的解决方案。软件行业充斥哲学滋味的作品十分多,比方《人月神话》。举个例子,当软件系统遇到性能问题,尝试上面两种哲学思想晋升性能: 空间换工夫:比方引入缓存,耗费额定的存储进步响应速度。工夫换空间:比方大文件的分片解决,分段解决后再汇总后果。设计持重高可用的零碎,尝试从三个方面思考问题: 存储:数据会失落吗,数据一致性怎么解决。计算:计算怎么扩容,利用容许任意减少节点吗。传输:网络中断或拥塞怎么办。从有数的失败或者胜利的教训中,总结出高度概括性的计划,让咱们下一步做的更好。 英语英语是极为重要的根底,学好英语与把握编程语言一样重要。且不说外企对英语的要求,许多出名博客就是把英文翻译成中文,充当常识的搬运工。如果英语足够好,间接浏览一手英语材料,防止别人翻译存在的舛误。 怎么学常识体系体系化的常识比零散的更容易记忆和了解,这正如一部好的电视剧,剧情环环相扣能力吸引观众。倡议大家应用思维导图列举知识点,构建体系结构,如下图所示: 有点被吃像素,想要清晰大图的敌人能够进群973961276获取啊,也能够聊聊技术吹吹牛, 而且每个礼拜都有几次送书流动,此时不进,更待何时? 零根底和大三大四的敌人看这里>>c/c++ 企业级我的项目实战曾经工作了想持续自我晋升跳槽涨薪的工程师看这里>>c/c++ linux服务器高级架构师学习 克服忘记高中是咱们常识的巅峰时刻,每周小考每月大考,教辅材料堆成山,天堂式的重复操练强化记忆。温习是反抗忘记的惟一方法。大脑的忘记是有法则的,先快后慢。一天后,学到的常识只剩下原来的25%,甚至更低。随着工夫的推移,忘记的速度减慢,忘记的数量也就缩小。 工夫距离 记忆量 刚看完 100% 20分钟后 60% 1小时后 40% 1天后 30% 2天后 27% 每个人的忘记水平都不一样,倡议第二天温习前一天的内容,七天后温习这段时间的所有内容。 碎片工夫不少敌人利用碎片工夫学习,比方在公交上看公众号的推送。其实咱们都高估了本人的抗干扰能力,如果处在嘈杂的环境,注意力容易被打断,记忆留存度也很低。碎片工夫适宜学习简略孤立的知识点,比方链表的定义与实现。学习简单的常识,须要大段的间断工夫。图书馆是个好中央,宁静气氛好。手机放一边,不要理睬QQ微信,最好浏览纸质书,泡上一整天。有些城市呈现了付费自习室,提供格子间、茶水等等,也是十分好的抉择。 用起来技术分享从上面这张图咱们能够看到,传授别人是常识留存率最高的形式。 筹备PPT和演讲内容,给共事来一场技术分享。不光温习常识,还锤炼口才。已经有个共事谈话又快又急,口头禅也多,比方"对吧、是不是”,他人常常听不清,然而他自己不以为然。领导让他做了几次技术分享,听众的反馈可想而知,他才彻底认清毛病。保持写技术博客,别在意你写的货色在网上曾经反复千百遍。当本人入手的时候,才会意识到眼高手低。让文章读起来晦涩清晰,须要醉生梦死的删改。写作是对大脑的长期考验,想不到必定写不出,想不分明必定写不分明。 造个轮子咱们常常说不要反复造轮子。为了开发效率,能够不造轮子,然而必须具备造轮子的能力。倡议造一个简略的MQ,你能用到通信协议、设计模式、队列等许多常识。在造轮子的过程中,你会频繁的翻阅各种手册或者博客,这就是用输入倒逼输出。

November 24, 2020 · 1 min · jiezi

关于c++:打造可复用的数据结构库3-顶层父类创建

1 顶层父类存在的意义C++ 的编译在有些轻微的中央存在雷同的代码在不同编译器下的编译的后果不同的浮现。例如:new失败当前,有些抛出异样,有的返回nullptr。有的编译器不反对异样···,所以要在内存的操作做一个对立的解决。尽量应用单继承形式解决,避免架构问题呈现。综上: 设计一个顶层父类,所有的数据结构都继承自这个类,这个类解决动态内存申请行为。 2 类的次要内容 class Object { public: void * operator new (unsigned int size ) throw(); void operator delete (void *p ) ; void * operator new[] (unsigned int size ) throw(); void operator delete[] (void *p ) ; virtual ~Object()=0; }3 类的实现void * Object :: operator new (unsigned int size ) throw(){ return malloc( size);}void Object :: operator delete (void *p ){ free( p);}void * Object :: operator new[] (unsigned int size ) throw(){ return malloc( size);}void Object :: operator delete[] (void *p ){ free( p);}Object :: ~Object(){}

November 22, 2020 · 1 min · jiezi

关于c++:面试必备最新整理出的腾讯C后台开发面试笔记

文章是由口试面试腾讯笔记整顿而来,次要是针对面试的C++后盾开发岗位,涵盖了大部分C++后盾开发相干可能会考查和被问到的技术点。自认为这篇笔记是比拟全面的总结,不论你是曾经工作筹备加入社招,还是在校学生筹备加入校招,笔记都能够作为技术面试筹备阶段参考查阅,查缺补漏。 笔记是根底C++知识点总结,没有过多的论述后盾开发的零碎架构和分布式后盾服务设计相干,还有c++11新个性,这些口试面试也会被问到但不在这篇探讨范畴,能够关注我前面有工夫再补上。 举荐视频:如何建设本人的常识体系,搭建本人的技术栈提供一张c/c++ linux后盾开发常识体系纲要,供大家查漏补缺↓↓↓ gdb调试命令step和next的区别?以后line有函数调用的时候,next会间接执行到下一句 ,step会进入函数. 查看内存(gdb)p &a //打印变量地址 (gdb)x 0xbffff543 //查看内存单元内变量 0xbffff543: 0x12345678 (gdb) x /4xb 0xbffff543 //单字节查看4个内存单元变量的值 0xbffff543: 0x78 0x56 0x34 0x12 多线程调试(gdb) info threads:查看GDB以后调试的程序的各个线程的相干信息 (gdb) thread threadno:切换以后线程到由threadno指定的线程 break filename:linenum thread all 在所有线程相应行设置断点,留神如果主线程不会执行到该行,并且启动all-stop模式,主线程执行n或s会切换过来 set scheduler-locking off|onstep 默认off,执行s或c其它线程也同步执行。on,只有以后线程执行。step,只有以后线程执行 show scheduler-locking 显示以后模式 thread apply all command 每个线程执行批准命令,如bt。或者thread apply 1 3 bt,即线程1,3执行bt。 查看调用堆栈(gdb)bt (gdb)f 1 帧简略信息 (gdb)info f 1 帧详细信息 断点b test.cpp:11 b test.cpp:main gdb attach 调试办法: ...

November 20, 2020 · 6 min · jiezi

关于c++:让你搞懂MYSQL底层原理-内部结构

一、一条SQL执行过程先看看一条查问SQL(这里提供一下官网对各存储引擎的文档阐明 Mysql存储引擎) 一条 update SQL执行update的执行 从客户端 => ··· => 执行引擎 是一样的流程,都要先查到这条数据,而后再去更新。要想了解 UPDATE 流程咱们先来看看,Innodb的架构模型。Innodb 架构上一张 MYSQL 官网InnoDB架构图:外部模块连接器(JDBC、ODBC等) => [MYSQL 外部 [Connection Pool] (受权、线程复用、连贯限度、内存检测等)=>[SQL Interface] (DML、DDL、Views等) [Parser] (Query Translation、Object privilege) [Optimizer] (Access Paths、 统计分析) [Caches & Buffers]=>[Pluggable Storage Engines] => [File] 二、内存构造这里有个关键点,当咱们去查问数据时候会先 拿着咱们以后查问的 page 去 buffer pool 中查问 以后page是否在缓冲池中。如果在,则间接获取。 而如果是update操作时,则会间接批改 Buffer中的值。这个时候,buffer pool中的数据就和咱们磁盘中理论存储的数据不统一了,称为脏页。每隔一段时间,Innodb存储引擎就会把脏页数据刷入磁盘。一般来说当更新一条数据,咱们须要将数据给读取到buffer中批改,而后写回磁盘,实现一次 落盘IO 操作。 为了进步update的操作性能,Mysql在内存中做了优化,能够看到,在架构图的缓冲池中有一块区域叫做:change buffer。顾名思义,给change后的数据,做buffer的,当更新一个没有 unique index 的数据时,间接将批改的数据放到 change buffer,而后通过 merge 操作实现更新,从而缩小了那一次 落盘的IO 操作。 咱们下面说的有个条件:没有惟一索引的数据更新时,为什么必须要没有惟一索引的数据更新时能力间接放入changebuffer呢?如果是有惟一束缚的字段,咱们在更新数据后,可能更新的数据和曾经存在的数据有反复,所以只能从磁盘中把所有数据读出来比对能力确定唯一性。所以当咱们的数据是 写多读少 的时候,就能够通过 减少 innodb_change_buffer_max_size 来调整 changebuffer在buffer pool 中所占的比例,默认25(即:25%)问题又来了,merge是如何运作的有四种状况: ...

November 19, 2020 · 1 min · jiezi

关于c++:浅谈UDP数据包长度收包能力丢包及进程结构选择

UDP数据包长度 UDP数据包的实践长度 udp数据包的实践长度是多少,适合的udp数据包应该是多少呢?从TCP-IP详解卷一第11章的udp数据包的包头能够看出,udp的最大包长度是2^16-1的个字节。因为udp包头占8个字节,而在ip层进行封装后的ip包头占去20字节,所以这个是udp数据包的最大实践长度是2^16-1-8-20=65507。 然而这个只是udp数据包的最大实践长度。首先,咱们晓得,TCP/IP通常被认为是一个四层协定零碎,包含链路层、网络层、运输层、应用层。UDP属于运输层,在传输过程中,udp包的整体是作为上层协定的数据字段进行传输的,它的长度大小受到上层ip层和数据链路层协定的制约。 【文章福利】小编举荐本人的linuxC/C++语言交换群:832218493!整顿了一些集体感觉比拟好的学习书籍、视频材料共享在群文件外面,有须要的能够自行添加哦!~ MTU相干概念 以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理个性决定的。这个1500字节被称为链路层的MTU(最大传输单元)。因特网协定容许IP分片,这样就能够将数据包分成足够小的片段以通过那些最大传输单元小于该数据包原始大小的链路了。这一分片过程产生在网络层,它应用的是将分组发送到链路上的网络接口的最大传输单元的值。这个最大传输单元的值就是MTU(Maximum Transmission Unit)。它是指一种通信协议的某一层下面所能通过的最大数据包大小(以字节为单位)。最大传输单元这个参数通常与通信接口无关(网络接口卡、串口等)。 在因特网协定中,一条因特网传输门路的“门路最大传输单元”被定义为从源地址到目标地址所通过“门路”上的所有IP跳的最大传输单元的最小值。 须要留神的是,loopback的MTU不受上述限度,查看loopback MTU值: [root@bogon ~]# cat /sys/class/net/lo/mtu 65536 IP分包udp数据包长度的影响 如上所述,因为网络接口卡的制约,mtu的长度被限度在1500字节,这个长度指的是链路层的数据区。对于大于这个数值的分组可能被分片,否则无奈发送,而分组替换的网络是不牢靠的,存在着丢包。IP 协定的发送方不做重传。接管方只有在收到全副的分片后能力 reassemble并送至下层协定解决代码,否则在应用程序看来这些分组曾经被抛弃。 假设同一时刻网络丢包的概率是均等的,那么较大的IP datagram必然有更大的概率被抛弃,因为只有失落了一个fragment,就导致整个IP datagram接管不到。不超过MTU的分组是不存在分片问题的。 MTU的值并不包含链路层的首部和尾部的18个字节。所以,这个1500字节就是网络层IP数据报的长度限度。因为IP数据报的首部为20字节,所以IP数据报的数据区长度最大为1480字节。而这个1480字节就是用来放TCP传来的TCP报文段或UDP传来的UDP数据报的。又因为UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为1472字节。这个1472字节就是咱们能够应用的字节数。 当咱们发送的UDP数据大于1472的时候会怎么呢?这也就是说IP数据报大于1500字节,大于MTU。这个时候发送方IP层就须要分片(fragmentation)。把数据报分成若干片,使每一片都小于MTU。而接管方IP层则须要进行数据报的重组。而更重大的是,因为UDP的个性,当某一片数据传送中失落时,接管不便无奈重组数据报。将导致抛弃整个UDP数据报。因而,在一般的局域网环境下,将UDP的数据管制在1472字节以下为好。 进行Internet编程时则不同,因为Internet上的路由器可能会将MTU设为不同的值。如果咱们假设MTU为1500来发送数据的,而途经的某个网络的MTU值小于1500字节,那么零碎将会应用一系列的机制来调整MTU值,使数据报可能顺利达到目的地。鉴于Internet上的规范MTU值为576字节,所以在进行Internet的UDP编程时,最好将UDP的数据长度控件在548字节(576-8-20)以内。 UDP丢包 udp丢包是指网卡接管到数据包后,linux内核的tcp/ip协定栈在udp数据包处理过程中的丢包,次要起因有两个: 1、udp数据包格局谬误或校验和查看失败。 2、应用程序来不及解决udp数据包。 对于起因1,udp数据包自身的谬误很少见,应用程序也不可控,本文不探讨。 首先介绍通用的udp丢包检测办法,应用netstat命令,加-su参数。 netstat -suUdp: 2495354 packets received 2100876 packets to unknown port received. 3596307 packet receive errors 14412863 packets sent RcvbufErrors: 3596307 SndbufErrors: 0 从下面的输入中,能够看到有一行输入蕴含了"packet receive errors",如果每隔一段时间执行netstat -su,发现行首的数字一直变大,表明产生了udp丢包。 上面介绍一下应用程序来不及解决而导致udp丢包的常见起因: 1、linux内核socket缓冲区设的太小 # cat /proc/sys/net/core/rmem_default ...

November 19, 2020 · 1 min · jiezi

关于c++:redis自述年轻MySQL不讲武德耗子尾汁

前言欢送各位进群973961276一起聊聊技术吹吹牛,每周都会有几次抽奖送专业书籍的流动,奖品虽不甚值钱,但也算个彩头不是 我是Redis你好,我是Redis,一个叫Antirez的男人把我带到了这个世界上。 说起我的诞生,跟关系数据库MySQL还挺有渊源的。 在我还没来到这个世界上的时候,MySQL过的很辛苦,互联网倒退的越来越快,它包容的数据也越来越多,用户申请也随之暴涨,而每一个用户申请都变成了对它的一个又一个读写操作,MySQL是苦不堪言。尤其是到“双11”、“618“这种全民购物狂欢的日子,都是MySQL受苦受难的日子。 据起初MySQL通知我说,其实有一大半的用户申请都是读操作,而且常常都是反复查问一个货色,节约它很多工夫去进行磁盘I/O。 起初有人就推敲,是不是能够学学CPU,给数据库也加一个缓存呢?于是我就诞生了! 出世不久,我就和MySQL成为了好敌人,咱们俩经常携手呈现在后端服务器中。 应用程序们从MySQL查问到的数据,在我这里注销一下,前面再须要用到的时候,就先找我要,我这里没有再找MySQL要。 为了方便使用,我反对好几种数据结构的存储: StringHashListSetSortedSetBitmap······因为我把注销的数据都记录在内存中,不必去执行慢如蜗牛的I/O操作,所以找我要比找MySQL要省去了不少的工夫呢。 可别小瞧这简略的一个扭转,我可为MySQL加重了不小的累赘!随着程序的运行,我缓存的数据越来越多,有相当局部工夫我都给它挡住了用户申请,这一下它可乐得清闲自在了! 有了我的退出,网络服务的性能晋升了不少,这都归功于我为数据库挨了不少枪子儿。 零根底和大三大四的敌人看这里>>c/c++ 企业级我的项目实战曾经工作了想持续自我晋升跳槽涨薪的工程师看这里>>c/c++ linux服务器高级架构师学习 技术问题加我WeChat:lingshengxy收费征询,有工夫会一一答复 缓存过期 && 缓存淘汰不过很快我发现事件不妙了,我缓存的数据都是在内存中,可是就算是在服务器上,内存的空间资源还是很无限的,不能无节制的这么存上来,我得想个办法,不然吃枣药丸。 不久,我想到了一个方法:给缓存内容设置一个超时工夫,具体设置多长交给应用程序们去设置,我要做的就是把过期了的内容从我外面删除掉,及时腾出空间就行了。 超时工夫有了,我该在什么时候去干这个清理的活呢? 最简略的就是定期删除,我决定100ms就做一次,一秒钟就是10次! 我清理的时候也不能一口气把所有过期的都给删除掉,我这外面存了大量的数据,要全面扫一遍的话那不晓得要花多久工夫,会重大影响我接待新的客户申请的! 工夫紧工作重,我只好随机抉择一部分来清理,能缓解内存压力就行了。 就这样过了一段日子,我发现有些个键值运气比拟好,每次都没有被我的随机算法选中,每次都能幸免于难,这可不行,这些长时间过期的数据始终霸占着不少的内存空间!气抖冷! 我眼里可揉不得沙子!于是在原来定期删除的根底上,又加了一招: 那些原来逃脱我随机抉择算法的键值,一旦遇到查问申请,被我发现曾经超期了,那我就绝不客气,立刻删除。 这种形式因为是被动式触发的,不查问就不会产生,所以也叫惰性删除! 可是,还是有局部键值,既逃脱了我的随机抉择算法,又始终没有被查问,导致它们始终绳之以法!而于此同时,能够应用的内存空间却越来越少。 而且就算退一步讲,我可能把过期的数据都删除掉,那万一过期工夫设置的很长,还没等到我去清理,内存就吃满了,一样要吃枣药丸,所以我还得想个办法。 我苦思好久,终于憋出了个大招:内存淘汰策略,这一次我要彻底解决问题! 我提供了8种策略供应用程序抉择,用于我遇到内存不足时该如何决策: noeviction:返回谬误,不会删除任何键值allkeys-lru:应用LRU算法删除最近起码应用的键值volatile-lru:应用LRU算法从设置了过期工夫的键汇合中删除最近起码应用的键值allkeys-random:从所有key随机删除volatile-random:从设置了过期工夫的键的汇合中随机删除volatile-ttl:从设置了过期工夫的键中删除剩余时间最短的键volatile-lfu:从配置了过期工夫的键中删除应用频率起码的键allkeys-lfu:从所有键中删除应用频率起码的键有了下面几套组合拳,我再也不必放心过期数据多了把空间撑满的问题了~ 缓存穿透 && 布隆过滤器我的日子过的还挺舒坦,不过MySQL大哥就没我这么舒坦了,有时候遇到些烦人的申请,查问的数据不存在,MySQL就要白忙活一场!不仅如此,因为不存在,我也没法缓存啊,导致同样的申请来了每次都要去让MySQL白忙活一场。我作为缓存的价值就没失去体现啦!这就是人们常说的缓存穿透。  这一来二去,MySQL大哥忍不住了:“唉,兄弟,能不能帮忙想个办法,把那些明晓得不会有后果的查问申请给我挡一下” 这时我想到了我的另外一个好敌人:布隆过滤器 我这位敌人别的本事没有,就善于从超大的数据集中疾速通知你查找的数据存不存在(轻轻通知你,我的这位敌人有一点不靠谱,它通知你存在的话不能全信,其实有可能是不存在的,不过它他要是通知你不存在的话,那就肯定不存在)。 我把这位敌人介绍给了应用程序,不存在的数据就不用去叨扰MySQL了,轻松帮忙解决了缓存穿透的问题。 缓存击穿 && 缓存雪崩这之后过了一段时间太平日子,直到那一天··· 有一次,MySQL那家伙正优哉游哉的摸鱼,忽然一大堆申请给他怼了过来,给他打了一个措手不及。 一阵忙活之后,MySQL火冒三丈的找到了我,“兄弟,咋回事啊,怎么一下子来的这么猛” 我查看了日志,连忙解释到:“大哥,切实不好意思,刚刚有一个热点数据到了过期工夫,被我删掉了,不巧的是随后就有对这个数据的大量查问申请来了,我这里曾经删了,所以申请都发到你那里来了” “你这干的叫啥事,下次留神点啊”,MySQL大哥一脸不快乐的来到了。 这一件小事我也没怎么放在心上,随后就抛之脑后了,却没曾想几天之后竟捅了更大的篓子。 那一天,又呈现了大量的网络申请发到了MySQL那边,比上一次的规模大得多,MySQL大哥一会儿功夫就给干趴下了好几次! 等了好半天这一波流量才算过来,MySQL才缓过神来。 “老弟,这一次又是什么起因?”,MySQL大哥累的没了力量。 “这一次比上一次更不巧,这一次是一大批数据简直同时过了有效期,而后又产生了很多对这些数据的申请,所以比起上一次这规模更大了” MySQL大哥听了眉头一皱,“那你倒是想个办法啊,三天两头折磨我,这谁顶得住啊?” “其实我也很无奈,这个工夫也不是我设置的,要不我去找应用程序说说,让他把缓存过期工夫设置的平均一些?至多别让大量数据个体生效” “走,咱俩一起去” 起初,我俩去找应用程序磋商了,不仅把键值的过期工夫随机了一下,还设置了热点数据永不过期,这个问题缓解了不少。哦对了,咱们还把这两次产生的问题别离取了个名字:缓存击穿和缓存雪崩。 咱们终于又过上了舒服的日子··· ...

November 19, 2020 · 1 min · jiezi

关于c++:C-多线程

CreateEventCreateEvent( __in_opt LPSECURITY_ATTRIBUTES lpEventAttributes, __in BOOL bManualReset, __in BOOL bInitialState, __in_opt LPCSTR lpName );bManualReset: 指定将事件对象创立成手动还原还是主动还原。如果是TRUE, 那么必须用ResetEvent函数来手工将事件的状态还原到无信号状态。 如果是FALSE,当事件被一个期待线程开释当前,零碎将会主动将事件状态还原为无信号状态。bInitialState:指定事件对象的初始状态; 当TRUE, 初始状态为有信号状态; 当FALSE, 初始状态为无信号状态。SetEvent / ResetEvent别离将EVENT置为这两种状态别离是有信号状态与无信号 WaitForSingleObject / WaitForMultipleObjectsWaitForSingleObject( _In_ HANDLE hHandle, _In_ DWORD dwMilliseconds ); 参数hHandle是一个事件的句柄,第二个参数dwMilliseconds是工夫距离。如果工夫是有信号状态返回WAIT_OBJECT_0,如果工夫超过dwMilliseconds值但工夫事件还是无信号状态则返回WAIT_TIMEOUT。WaitForSingleObject 的返回值有以下三种状况:WAIT_OBJECT_0:示意你期待的对象(比方线程、互斥体)已的失常执行实现或实现开释。WAIT_TIMEOUT:示意你期待的对象在还没实现之前,由 WaitForSingleObject 设置的工夫曾经超时。WAIT_ABANDONED:这是针对期待对象是互斥体的状况,当互斥体对象尽管没有被占用它的线程开释,然而占用它的线程已提前停止时,WaitForSingleObject 就返回此值。WaitForSingleObject函数用来检测 hHandle事件的信号状态当函数的执行工夫超过dwMilliseconds就返回,如果参数dwMilliseconds为INFINITE时 函数将直到相应工夫事件变成有信号状态才返回,否则就始终期待上来,直到WaitForSingleObject有返回直才执行前面的代码。

November 19, 2020 · 1 min · jiezi

关于c++:理解复杂数组声明

默认状况下,类型修饰符从右向左顺次绑定。例如: int *ptrs[10] 代表的就是一个大小为10的数组,它的名字是ptrs,外面寄存的内容是指向int的指针。 然而碰到比较复杂的数组申明,例如: int (*Parray)[10] = &arr 就要从外向外读,首先读括号外面的局部,×Parray意味着Parray是一个指针,接下来察看左边,可晓得Parray是一个指向大小为10的数组的指针,最初察看右边,晓得数组中的元素是int。 int (&arrRef)[10] = arr; 在下面这个例子中,arrRef是一个援用,它援用的对象是一个大小位10的数组,数组中元素的类型是int。 ps:int &ref[10] = /* ? */ 谬误,不存在援用的数组

November 18, 2020 · 1 min · jiezi

关于c++:C调用Go方法的字符串传递问题及解决方案

摘要:C++调用Go办法时,字符串参数的内存治理须要由Go侧进行深度值拷贝。景象在一个APP技术我的项目中,子过程按申请加载Go的ServiceModule,将须要拉起的ServiceModule信息传递给Go的Loader,存在C++调用Go办法,传递字符串的场景。 计划验证时,发现有奇怪的将std::string对象的内容传递给Go办法后,在Go办法协程中取到的值与预期不统一。 通过一段时间的剖析和验证,终于了解问题产生的起因并给出解决方案,现分享如下。 背景常识Go有本人的内存回收GC机制,通过make等申请的内存不须要手动开释。C++中为std::string变量赋值新字符串后,.c_str()和.size()的后果会联动变动,尤其是.c_str()指向的地址也有可能变动。go build -buildmode=c-shared .生成的.h头文件中定义了C++中Go的变量类型的定义映射关系,比方GoString、GoInt等。其中GoString理论是一个构造体,蕴含一个字符指针和一个字符长度。原理及解释通过代码示例形式解释具体景象及起因,详见正文 C++侧代码: // // Created by w00526151 on 2020/11/5. //#include <string> #include <iostream> #include <unistd.h> #include "libgoloader.h" /** * 结构GoString构造体对象 * @param p * @param n * @return */ GoString buildGoString(const char* p, size_t n){ //typedef struct { const char *p; ptrdiff_t n; } _GoString_; //typedef _GoString_ GoString; return {p, static_cast<ptrdiff_t>(n)};} int main(){ std::cout<<"test send string to go in C++"<<std::endl; std::string tmpStr = "/tmp/udsgateway-netconftemplateservice"; printf("in C++ tmpStr: %p, tmpStr: %s, tmpStr.size:%lu rn", tmpStr.c_str(), tmpStr.c_str(), tmpStr.size()); { //通过new新申请一段内存做字符串拷贝 char *newStrPtr = NULL; int newStrSize = tmpStr.size(); newStrPtr = new char[newStrSize]; tmpStr.copy(newStrPtr, newStrSize, 0); //调用Go办法,第一个参数间接传std::string的c_str指针和大小,第二个参数传在C++中独自申请的内存并拷贝的字符串指针,第三个参数和第一个一样,然而在go代码中做内存拷贝保留。 //调用Go办法后,通过赋值批改std::string的值内容,期待Go中新起的线程10s后再将三个参数值打印进去。LoadModule(buildGoString(tmpStr.c_str(), tmpStr.size()), buildGoString(newStrPtr, newStrSize), buildGoString(tmpStr.c_str(),tmpStr.size())); //批改tmpStr的值,tmpStr.c_str()失去的指针指向内容会变动,tmpStr.size()的值也会变动,Go中第一个参数也会受到影响,前几位会变成新字符串内容。 //因为在Go中int是值拷贝,所以在Go中,第一个参数的长度没有变动,因而理论在Go中曾经呈现内存越界拜访,可能产生Coredump。 ...

November 18, 2020 · 2 min · jiezi

关于c++:Redis为什么变慢了这些原因你都知道吗

前言Redis作为内存数据库,领有十分高的性能,单个实例的QPS可能达到10W左右。但咱们在应用Redis时,常常时不时会呈现拜访提早很大的状况,如果你不晓得Redis的外部实现原理,在排查问题时就会一头雾水。 很多时候,Redis呈现拜访提早变大,都与咱们的使用不当或运维不合理导致的。 这篇文章咱们就来剖析一下Redis在应用过程中,常常会遇到的提早问题以及如何定位和剖析。 欢送各位进群973961276一起聊聊技术吹吹牛,每周都会有几次抽奖送专业书籍的流动,奖品虽不甚值钱,但也算个彩头不是 应用复杂度高的命令如果在应用Redis时,发现拜访提早忽然增大,如何进行排查? 首先,第一步,倡议你去查看一下Redis的慢日志。Redis提供了慢日志命令的统计性能,咱们通过以下设置,就能够查看有哪些命令在执行时提早比拟大。 首先设置Redis的慢日志阈值,只有超过阈值的命令才会被记录,这里的单位是奥妙,例如设置慢日志的阈值为5毫秒,同时设置只保留最近1000条慢日志记录: # 命令执行超过5毫秒记录慢日志CONFIG SET slowlog-log-slower-than 5000# 只保留最近1000条慢日志CONFIG SET slowlog-max-len 1000 设置实现之后,所有执行的命令如果提早大于5毫秒,都会被Redis记录下来,咱们执行SLOWLOG get 5查问最近5条慢日志: 127.0.0.1:6379> SLOWLOG get 51) 1) (integer) 32693 # 慢日志ID 2) (integer) 1593763337 # 执行工夫 3) (integer) 5299 # 执行耗时(奥妙) 4) 1) "LRANGE" # 具体执行的命令和参数 2) "user_list_2000" 3) "0" 4) "-1"2) 1) (integer) 32692 2) (integer) 1593763337 3) (integer) 5044 4) 1) "GET" 2) "book_price_1000"... 通过查看慢日志记录,咱们就能够晓得在什么工夫执行哪些命令比拟耗时,如果你的业务常常应用O(N)以上复杂度的命令,例如sort、sunion、zunionstore,或者在执行O(N)命令时操作的数据量比拟大,这些状况下Redis解决数据时就会很耗时。 如果你的服务申请量并不大,但Redis实例的CPU使用率很高,很有可能是应用了复杂度高的命令导致的。 解决方案就是,不应用这些复杂度较高的命令,并且一次不要获取太多的数据,每次尽量操作大量的数据,让Redis能够及时处理返回。 ...

November 18, 2020 · 1 min · jiezi

关于c++:读完某C神作我只记住了100句话

假如p是指针,当delete p;时,前面肯定要p=NULL将p指向空cin cout cerr 都是iostream类型的对象。cout\<\<"hello world"\<\<endl; 其中cout是左操作数对象,\<\<是操作符,作用是将右操作数写到左操作数对象,"hello world"是右操作数,后面半句话的意思是将hello world写入cout对象。同理,\<\<endl是将endl写入cout,endl示意刷新缓冲区并换行。std::cout ::是作用域操作符,示意std名空间下的cout,用来区别其它名空间同名变量。正文不能嵌套:/\ /\...\/ \/ 是谬误的示意整数、字符和布尔值的算术类型合称为整形。辨别类型是因为只有晓得某地址值的类型,能力晓得须要多少位示意这个变量和如何解释这些位。整形赋值超出取值范畴,会被赋值数对该类型数值数目取模后的值。long类型运行时代价远高于int类型。以0结尾的字面值常量示意八进制、以0x结尾的示意十六进制。任何字符能够示意为 \ooo【ooo示意一个八进制数】对象是内存中具备类型的区域。初始化不是赋值,初始化是创立并赋值。定义在函数体外的内置变量主动初始化成0,定义在函数体内的内置变量不进行主动初始化,类类型\(string\)调用默认构造函数初始化。const把一个对象转换成一个常量【const int bufSize = 512】。 全局变量加const作用域只在本文件。再加extern可在整个程序拜访。非const变量默认为extern。援用初始化后始终绑定到初始化的对象,不能扭转【援用自身不占存储单元】。const对象必须由const援用指向【防止一个能批改,一个不能批改,既对象自身和代表其的援用必须同时为const】。一般援用不能初始化为常量,const援用能够。typedef用来定义类型的同义词。头文件用于申明,不是定义,因此能够呈现屡次。定义的语句不应该放在头文件里,呈现两次会导致多重定义链接谬误。例外是头文件能够定义类,还有值在编译时就曾经晓得的const对象,还有inline函数。变量是申明还是定义看是否有extern,但不是相对的,函数就看有无大括号\{\}两个迭代器指向同一个元素就相等【==】,否则不等。任何扭转vector长度的操作都会使已存在的迭代器生效。difference\_type存储迭代器间间隔。设计良好的程序只有在强调速度时才在类实现的外部应用数组和指针。数组下标的正确类型是size\_t。预处理器变量NULL在编译时会被数值0替换。指针做减法操作失去的是ptrdiff\_t类型。指针p - 2 等效p\[-2\]。定义的多个变量具备雷同的类型,就能够在for循环的初始化语句中同时定义他们。for\(int a, b, c ...\)C++强制要求指向const对象的指针也必须具备const个性,能够把非const对象地址赋给const指针。const指针:int \*const cur = \&cuss; 指向int型变量的指针,并且自身不能批改。C格调字符串:const char \*cp = "some value"; strlen\(用于计算c格调字符串字符个数,不包含串最初的'\0'\)动静数组:int \*p = new int\[任意表达式,变量等\] delete \[\] p;new/delete是操作符,岂但管制内存而且执行构造函数和析构函数,malloc/free是规范库函数,不在编译器管制权限内,不能执行结构和析构。应用数组初始化vector:int int_arr[arr_size] = {0,1,2,3}; vector<int> ivec(int_arr, int_arr+arr_size);int ival; int \*pval; ival = pval = 0; 谬误,pval = 0 返回的是指针,无奈赋值给int。++i i++ 前置时返回自增后的值,后置时返回值后自增。前置性能好于后置。逗号表达式的后果是其最左边表达式的值。if\(ia\[index++\]\<ia\[index\]\)这个表达式没有明确的计算程序。除了 \&\& || \?::外其余操作数没有规定计算程序。不应该应用这种表达式,后果无奈确定。int val = 3.24+3;表达式先转换为高精度,再转换为左值类型。int \*ip; ip=0;隐式转换0为空指针。蕴含signed和unsigned int的表达式会被转换成unsigned,如果为正数会有问题。数组名用做sizeof或取地址\&的操作数时不被当做指针。sizeof计算栈中调配大小,动态变量在全局数据区不计算在内。const\_cast增加或删除const个性。空语句: ;switch case break的判断表达式必须为整数值。case从匹配的开始执行直到完结,而不是只执行匹配的。do\{此处定义的变量循环条件中不可见\}while\(...\)throw 类型 每一个规范库异样类都有what\(\)函数返回C格调用户输出的字符串。如果不存在catch语句,程序默认执行terminate的规范库函数。预处理器定义的调试用的常量:\\_FILE\\ \\LINE\\ \\TIME\\ \\DATE\\_【打印工夫和日期很罕用】assert宏用来查看不可能产生的条件。函数实参如果和定义类型不统一,但可被转换成定义类型,那么也能够应用。如果须要爱护指针指向的值,形参须要定义为指向const的指针。应将不批改实参的形参定义为const援用,益处是能够传递字符串字面值(和产生右值的表达式),非const援用反而不灵便。如果形参是援用,那么他只是实参的别名。int \*\&v v是援用,是某个指向int的指针的别名。fun\(int\*\) fun\(int\[\]\) fun\(int\[10\]\)等价,但10其实没有任何用途。如果定义为fun\(int \(\&arr\)\[10\]\),此时会查看参数是否有10个。C格调字符串以NULL结尾是为了标识完结避免越界含有可变形参的函数:fun(parm_list, ...)与省略符对应的实参暂停类型查看。 ...

November 17, 2020 · 1 min · jiezi

关于c++:CC语言知识总结函数执行过程js变量提升和和this指向

一、函数被调用 1、函数不存在,报错。 2、函数存在,进入调用函数贮存栈(先入后出),期待此函数外部函数调用实现后,在继续执行此函数。 变量晋升 1、初始化arguments变量2、外部变量晋升和函数晋升2.1、函数名和变量名重名时候,函数名优先级大于变量名。例如: `// 函数名优先级大于变量名function test(){ console.log(a); // ƒ a(){} var a = 1; function a(){}; var a = function (){}; }test();` * 1* 2* 3* 4* 5* 6* 7* 82.2、函数晋升是剪切,不是复制。例如: `// 函数晋升是剪切,不是拷贝function test(){ console.log(a); // ƒ a(){} var a = 1; function a(){}; console.log(a); // 1 在这里的值不是 'ƒ a(){}' 的起因是,函数a变量晋升时候被剪切到了结尾 var a = 2; console.log(a); // 2}test();` * 1* 2* 3* 4* 5* 6* 7* 8* 9* 10创立作用域链建设作用域链,不便找到对应的变量是否有值。 ...

November 17, 2020 · 1 min · jiezi

关于c++:C-之父C-是一切的无形基础透露编程语言生存-40-年秘诀

C++ 的起源能够追溯到 40 年前,但它依然是当今应用最宽泛的编程语言之一。 到 2020 年 9 月为止,C++ 是仅次于 C 语言、Java 和 Python,位于寰球第四的编程语言。依据最新的 TIOBE 索引,C++ 也是增长最快的语言。 近日,C++ 之父 Bjarne Stroustrup 在承受外媒访谈的时候,对 C++ 胜利的要害和 它40 年来的倒退历程进行了回顾。 C++ 的胜利属于意料之外1979 年,C++ 的创建者 Bjarne Stroustrup 开始着手开发这种编程语言,该语言最后被设计为对 C 语言对改进版,减少了基于面向对象编程的性能。 Bjarne Stroustrup 一开始没想到 C++ 会取得如此大的胜利,他说:“C++ 的胜利显然令人诧异。我认为它的胜利取决于其最后的设计指标,就是无效的应用硬件,再加上弱小的形象机制,以及它依据来自理论应用状况的反馈进行审慎的倒退。” 构建 C++ 之初,Bjarne Stroustrup 心愿用通信零碎构建一个多计算机系统,该通信零碎能够是共享内存,也能够是网络。他把重点放在了软件上,去编写底层的、靠近硬件的代码。例如存储管理器,过程调度程序和设施驱动程序,以及拆散软件组件,便于它们能够在运行应用更好的形式运行。 40 年前,是没有编程语言能够胜任这项工作的,Bjarne Stroustrup 对此花了很多心理。 当初,C++ 曾经成为了最受开发人员欢送的语言之一,坚固了寰球的零碎和服务。 C++ 11 使 C++ 成为一种新的语言他从很早开始就意识到了这项工作不可能由他一个人来实现,但过后也只有 Bjarne Stroustrup 和他在贝尔实验室的几个共事全身心的投入其中。随着标准化过程放慢,退出其中的人也越来越多,现在 C++ 规范委员会已有了 400 多名成员和更宽泛的用户群体,他们共同努力影响着编程语言的倒退方向。 1998 年是 C++ 正式标准化的一年,从那时起它就成了工夫是最罕用的编程语言之一,并至今都放弃着这种位置。 ...

November 17, 2020 · 1 min · jiezi

关于c++:未来几年都能用的CCLinux服务器开发高级架构体系

依据IT行业c/c++后盾开发岗位技术需要定制全新晋升技术体系。将来几年都能用上。 十大专栏技术点,外加每一个技术点的举荐书籍。 专一于C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等等多个知识点高级技术分享。 所有技术点原理+我的项目相结合解说,实现与我的项目的字眼,都是纯手写代码去实现。 一:精进基石专栏三个点:数据架构与算法,设计模式,工程治理 二:高性能网络设计专栏技术点:tcp服务器如何降级https服务器,epoll的实现,reactor的原理与实现,百万并发,websocket协定,Redis,memcached。nginx网络组件.UDP牢靠传输,QUIC,kcp.posixAPI网络协议栈 三:根底组件实现专栏技术点:手写线程池,ringbuffer,内存池实现,mysql连接池的实现,Redis连接池的实现。 原子操作CAS,音讯队列与无锁实现,保活设计,锁原理。TRY/catch组件实现。 libev.libevent框架实战,异步日志,openssl对称加密与非对称加密,json数据解析xml数据解析器,字符编码Unicode原理编程实战 四:自研框架专栏技术点:协程框架实现NtyCo、用户态协定栈NtyTCP,纯我的项目解说,原理到我的项目实现。 五:中间件开发专栏技术点:五大技术点:Mysgl、redis、Nginx、monfoDB、dfs。 三大维度去讲:源码剖析,集群计划解说,我的项目实现 六:根底开源框架专栏技术点:skynet源码剖析,我的项目实现。 zeroMQ源码剖析,我的项目实现,性能剖析。 dpdk原理,我的项目实现。 七:Linux内核源码专栏技术点:过程治理,内存治理,文件系统,设施驱动 从原理到我的项目来解说 八:性能剖析专栏技术点:高性能构建零碎tundra 性能工具:wrK、webbench 调试库:内存调试性能剖析工具Valgrind,谷歌c++测试框架GoogleTest,内存调配跟踪库MemTrack 内核跟踪:内核探测Systemtap、热图剖析与生成 九:分布式架构专栏技术点:架构实战:腾讯微服务RPC框架Tars、虚拟化Docker与容器编排 架构原理与实战:分布式注册服务中心etcb。快播核心技术P2P框架的实现 十:我的项目实战专栏互联网并发云盘,微服务即时通讯。两大我的项目从原理解说到产品上线公布。手写代码实现 十一:配套参考书籍材料举荐重要技术点的书籍举荐心愿大家依据这个技术体系学有所成,相干技术点宣讲视频能够加群:832218493收费支付!

November 16, 2020 · 1 min · jiezi

关于c++:初学小白学习CC基本知识笔记数组与字符

一、介绍数组一个常量变量就是一个用来存储数值的命名区域。同样,一个数组就是一个用来存储一系列变量值的命名区域,因而,能够应用数组组织常量变量。也就是说,数组是一组有序数据的汇合,存储在数组中的值称为数组元素。每个数组元素有一个相干的索引(也称为关键字),它能够用来拜访元素。在大多数编程语言中,数组都具备数字索引,而且这些索个通常是从0或1开始的。数组中的每个元素都属于同一个数据类型。一维数组是由数字组成的以单纯的排序构造排列的构造繁多的数组。一维数组是计算机程序中最根本的数组。二维及多维数组能够看作是一维数组的屡次叠加产生的。 二、一维数组当数组中每个元素都只带有一个下标时,称这样的数组为一维数组。通过给出的数组名称和这个元素在数组中的地位编号(即下标),程序能够援用数组中的任意一个元素,一维数组的援用定义格局为:类型+数组名[下标] 如:int a[10]其中,a是一维数组的数组名,该数组有10个元素,顺次示意为a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]。须要留神的是,数组是从零开始是,所以a[10]不属于这一个数组的空间范畴中。当在阐明局部定义了一个数组变量后,编译程序会在内存空间中开拓一串间断的存储单元。对于数组而言,程序的执行局部应用的是数组变量而不是数组类型。在援用时,下标必须是整数,但能够是整型变量或整型表达式。如果应用表达式,会先计算表达式以确定下标。程序只能一一利用数组中的元素而不能一次援用整个数组,再定义数组时,须要指定数组中元素的个数,方括号里边的常量数值示意了数组的长度。在数组定义前加const关键字可将整个数组变为只读,将不再能够对数组进行写入数据。 如: int a; float a[10]; (非法) int n=5; int a[n];(非法) int a[5+6]; (非法的) 初始化:(留神,在应用数组之前,肯定要先初始化) 1、数组的初始化能够在定义时一并实现 2、能够只给局部元素赋初值,其余的元素赋0。 3、如给全副元素赋值,则在数组中阐明,能够不给出数组元素的个数 4、数组的初始化能够是用循环进行输出数值赋值,也能够是在程序中指定赋值 例子: #include<stdio.h>//寻找数字并查看在哪个地位int search(int n, int a[], int max);int main(void) { int a[] = {1,6,5,7,4,3,2,8,11,9,10};//初始化一 /* int a[10] = {0}//初始化二 全都初始化为零 for (i = 0; i < 10; i++) {//初始化三本人输出初始化(这种初始化最好定义在二之上,否则其余如果有元素没有被赋值的话会出错) scanf("%d", &a[i]); } */ int n; scanf("%d", &n); //整个数组占用的字节数可用sizeof(a)示意进去 int h = search(n, a, sizeof(a) / sizeof(a[0]));//用整个数组占用的字节数除以首元素的字节数可晓得数组的大小 if (h != -1) { printf("%d在第%d位上", n, h+1); }else { printf("没有这个数字"); } return 0;}int search(int n, int a[], int max) { int t = -1; int i; for (i = 0; i < max; i++) {//遍历数组 if (n == a[i]) { t = i; break; } } return t;} 学习材料(工具安装包)支付 ...

November 16, 2020 · 3 min · jiezi

关于c++:这是你没见过的不一样的redis

提到Redis,大家肯定会想到的几个点是什么呢? 高并发,KV存储,内存数据库,丰盛的数据结构,单线程(6版本之前) 那么,接下来,下面提到的这些,都会一一给大家解答,带大家领略一下Redis的魅力,文章会比拟长,局部废话,请大家跳过,谢谢!~ 欢送进群973961276一起聊聊技术吹吹牛,每周都会有几次抽奖送专业书籍的流动,奖品不甚值钱,但也算个搏个彩头 =========================== 为什么会呈现缓存?个别状况下,数据都是在数据库中,利用零碎间接操作数据库。当访问量上万,数据库压力增大,这个时候,怎么办呢? 有小伙伴会说了,分库分表,读写拆散。确实,这些的确是解决比拟高的访问量的解决办法,然而,如果访问量更大,10万,100万呢?怎么分仿佛都不解决问题吧,所以咱们须要用到其余方法,来解决高并发带来的数据库压力。 这个时候,缓存呈现了,缓存,顾名思义,就是先把数据缓存在内存中一份,当拜访的时候,咱们会先拜访内存的数据,如果内存中的数据不存在,这个时候,咱们再去读取数据库,之后把数据库中的数据再备份一份到内存中,这样下次读申请过去的时候,还是会间接先从内存中拜访,拜访到内存的数据了之后就间接返回了。这样做就完满的升高了数据库的压力,可能十万个申请进来,全副都拜访了内存中备份的数据,而没有去拜访数据库,或者说只有大量的申请拜访到了数据库,这样真的是大大降低了数据库的压力,而且这样做也进步了零碎响应,大家想一下,内存的读写速度是远远大于硬盘的读写速度的,一个申请进来读取的内存能够比读取硬盘快很多很多,用户的体验也会很高。 什么是缓存呢?缓存原指CPU上的一种高速存储器,它先于内存与CPU替换数据,速度很快 当初泛指存储在计算机上的原始数据的复制集,便于快速访问。 在互联网技术中,缓存是零碎疾速响应的关键技术之一。 不足我的项目实战经验和想跳槽涨薪或是自我晋升的敌人看这里>>c/c++ 我的项目实战/后盾服务器开发高级架构师 感觉文字不好了解的敌人能够配合这个视频一起看>>redis、nginx及skynet源码剖析探索(上) =========================== 缓存的读写模式缓存有三种读写模式 Cache Aside Pattern(罕用)Cache Aside Pattern(旁路缓存),是最经典的缓存+数据库读写模式 读的时候,先读缓存,缓存没有的话,就读数据库,而后取出数据后放入缓存,同时返回响应。 更新的时候,先更新数据库,而后再删除缓存 为什么是删除缓存,而不是更新缓存呢? 1.缓存的值是一个构造,hash,list,更新数据须要遍历 2.懒加载,应用的时候才更新缓存,也能够采纳异步的形式填充缓存 高并发脏读的三种状况 1.先更新数据库,在更新缓存 update与commit之间,更新缓存,commit失败,则DB与缓存数据不统一 2.先删除缓存,再更新数据库 update与commit之间,有新的读,缓存空,读DB数据到缓存,数据是旧的数据 commit后DB为新的数据 则DB与缓存数据不统一 3.先更新数据库,再删除缓存(举荐) update与commit之间,有新的读,缓存空,读DB数据到缓存,数据是旧的数据 commit后DB为新的数据 则DB与缓存数据不统一 采纳延时双删策略 Read/Write Through Pattern应用程序只操作缓存,缓存操作数据库 Read-Through(穿透读模式/直读模式):应用程序读缓存,缓存没有,由缓存回源到数据库,并写入缓存 Write-Through(穿透写模式/直写模式):应用程序写缓存,缓存写数据库。该种模式须要提供数据库的handler,开发较为简单 Write Behind Caching Pattern应用程序只更新缓存 缓存通过异步的形式将数据批量或合并后更新到DB中 不能时时同步,甚至会丢数据 而Redis又是什么呢?Redis是一个高性能的开源的,C语言写的NoSQL(非关系型数据库)也叫做缓存数据库,数据保留在内存中。Redis是以key-value模式存储,和传统的关系型数据库不一样。不肯定遵循传统数据库的那些根本要求。比方,不遵循SQL规范,事务,表构造等。Redis有十分丰盛的数据类型,比方String,list,set,zset,hash等 Redis能够做一些什么呢?下面说的能够加重数据库压力,进步并发量,进步零碎响应工夫做Session拆散传统的Session是由本人的tomcat进行保护和治理的,在集群和分布式状况下,不同的tomcat要治理不同的session,只能在各个tomcat之间,通过网络和IO进行session复制,极大的影响了零碎的性能 Redis解决了这一个问题,将登陆胜利后的session信息,寄存在Redis中,这样多个tomcat就能够共享Session信息了 做分布式锁个别Java中的锁都是多线程锁,是在一个过程中的,多个过程在并发的时候也会产生问题,也要管制时序性,这个时候Redis能够用来做分布式锁,应用Redis的setnx命令来实现 用Redis做缓存,有这么有多长处,那么,毛病是不是也会对应的有很多呢? 额定的硬件收入缓存是一种软件系统中以空间换工夫的技术,须要额定的磁盘空间和内存空间来存储数据 高并发缓存生效在高并发的状况下,会呈现缓存生效(缓存穿透,缓存雪崩,缓存击穿等问题)造成霎时数据库访问量增大,甚至解体,所以这些问题是肯定要去解决的 缓存与数据库数据同步缓存与数据库无奈做到数据的时时同步 缓存并发竞争多个Redis客户端同时对一个key进行set值的时候因为执行程序引起的并发的问题 Redis的装置这里就不说了,mac,windows,linux网上各种装置教程,很多,大家去网上搜搜跟着做就ok了,比较简单,接下来,带着大家来剖析一下,Redis中的一些常见的数据类型吧。 Redis的数据结构Redis是一个key-value的存储系统,key的类型是字符串 ...

November 16, 2020 · 4 min · jiezi

关于c++:如果你之前还没听过DPDK那我宣布你现在已经掌握了

一、网络IO的处境和趋势从咱们用户的应用就能够感触到网速始终在晋升,而网络技术的倒退也从1GE/10GE/25GE/40GE/100GE的演变,从中能够得出单机的网络IO能力必须跟上时代的倒退。 1. 传统的电信畛域 IP层及以下,例如路由器、交换机、防火墙、基站等设施都是采纳硬件解决方案。基于专用网络处理器(NP),有基于FPGA,更有基于ASIC的。然而基于硬件的劣势非常明显,产生Bug不易修复,不易调试保护,并且网络技术始终在倒退,例如2G/3G/4G/5G等挪动技术的变革,这些属于业务的逻辑基于硬件实现太苦楚,不能疾速迭代。传统畛域面临的挑战是急需一套软件架构的高性能网络IO开发框架。 2. 云的倒退 公有云的呈现通过网络性能虚拟化(NFV)共享硬件成为趋势,NFV的定义是通过规范的服务器、规范交换机实现各种传统的或新的网络性能。急需一套基于罕用零碎和规范服务器的高性能网络IO开发框架。 3. 单机性能的飙升 网卡从1G到100G的倒退,CPU从单核到多核到多CPU的倒退,服务器的单机能力通过横行扩大达到新的高点。然而软件开发却无奈跟上节奏,单机解决能力没能和硬件门当户对,如何开发出与时并进高吞吐量的服务,单机百万千万并发能力。即便有业务对QPS要求不高,次要是CPU密集型,然而当初大数据分析、人工智能等利用都须要在分布式服务器之间传输大量数据实现作业。这点应该是咱们互联网后盾开发最应关注,也最关联的。 想理解更多的小伙伴欢送进群973961276来一起交流学习,更有海量学习材料跟大厂面试教训分享。 二、Linux + x86网络IO瓶颈在数年前已经写过《网卡工作原理及高并发下的调优》一文,形容了Linux的收发报文流程。依据教训,在C1(8核)上跑利用每1W包解决须要耗费1%软中断CPU,这意味着单机的下限是100万PPS(Packet Per Second)。从TGW(Netfilter版)的性能100万PPS,AliLVS优化了也只到150万PPS,并且他们应用的服务器的配置还是比拟好的。假如,咱们要跑满10GE网卡,每个包64字节,这就须要2000万PPS(注:以太网万兆网卡速度下限是1488万PPS,因为最小帧大小为84B《Bandwidth, Packets Per Second, and Other Network Performance Metrics》),100G是2亿PPS,即每个包的解决耗时不能超过50纳秒。而一次Cache Miss,不论是TLB、数据Cache、指令Cache产生Miss,回内存读取大概65纳秒,NUMA体系下跨Node通信大概40纳秒。所以,即便不加上业务逻辑,即便纯收发包都如此艰巨。咱们要管制Cache的命中率,咱们要理解计算机体系结构,不能产生跨Node通信。 从这些数据,我心愿能够间接感受一下这里的挑战有多大,现实和事实,咱们须要从中均衡。问题都有这些 1.传统的收发报文形式都必须采纳硬中断来做通信,每次硬中断大概耗费100微秒,这还不算因为终止上下文所带来的Cache Miss。 2.数据必须从内核态用户态之间切换拷贝带来大量CPU耗费,全局锁竞争。 3.收发包都有零碎调用的开销。 4.内核工作在多核上,为可全局统一,即便采纳Lock Free,也防止不了锁总线、内存屏障带来的性能损耗。 5.从网卡到业务过程,通过的门路太长,有些其实未必要的,例如netfilter框架,这些都带来肯定的耗费,而且容易Cache Miss。 三、DPDK的基本原理从后面的剖析能够得悉IO实现的形式、内核的瓶颈,以及数据流过内核存在不可控因素,这些都是在内核中实现,内核是导致瓶颈的起因所在,要解决问题须要绕过内核。所以支流解决方案都是旁路网卡IO,绕过内核间接在用户态收发包来解决内核的瓶颈。 Linux社区也提供了旁路机制Netmap,官网数据10G网卡1400万PPS,然而Netmap没宽泛应用。其起因有几个: 1.Netmap须要驱动的反对,即须要网卡厂商认可这个计划。 2.Netmap依然依赖中断告诉机制,没齐全解决瓶颈。 3.Netmap更像是几个零碎调用,实现用户态间接收发包,性能太过原始,没造成依赖的网络开发框架,社区不欠缺。 那么,咱们来看看倒退了十几年的DPDK,从Intel主导开发,到华为、思科、AWS等大厂商的退出,外围玩家都在该圈子里,领有欠缺的社区,生态造成闭环。晚期,次要是传统电信畛域3层以下的利用,如华为、中国电信、中国移动都是其晚期使用者,交换机、路由器、网关是次要利用场景。然而,随着下层业务的需要以及DPDK的欠缺,在更高的利用也在逐渐呈现。 DPDK旁路原理: 图片引自Jingjing Wu的文档《Flow Bifurcation on Intel® Ethernet Controller X710/XL710》 右边是原来的形式数据从 网卡 -> 驱动 -> 协定栈 -> Socket接口 -> 业务 左边是DPDK的形式,基于UIO(Userspace I/O)旁路数据。数据从 网卡 -> DPDK轮询模式-> DPDK根底库 -> 业务 用户态的益处是易用开发和保护,灵活性好。并且Crash也不影响内核运行,鲁棒性强。 ...

November 15, 2020 · 2 min · jiezi

关于c++:c11强化知识点

初始化列表(std::initializer_list)c++11提供了std::initializer_list,将使得类对象的初始化也能够和一般数组或者POD数据一样应用初始化列表的形式。只有为类对象提供初始化列表构造函数即可。std::initializer_list也能够作为函数的参数应用。初始化列表std::initializer_list相干示例代码如下。#include <iostream>#include <initializer_list>#include <vector>using namespace std;class InitClass {public: InitClass(initializer_list<int> list) { for (int l : list) initializer_list_.emplace_back(l); } void PrintInit() { for (int l : initializer_list_) cout << l << endl; } void Print(initializer_list<int> list) { for (int l : list) cout << l << endl; }private: vector<int> initializer_list_;};struct A { double a; int b;};struct B { B(int a, double b): a_(a), b_(b) {}private: int a_; double b_;};int main(){ // 应用初始化列表初始化类对象 InitClass i = {1, 2, 3, 4, 5}; i.PrintInit(); cout << endl; // 初始化列表做函数参数 i.Print({1, 2, 3}); // 应用初始化列表初始化POD数据 vector<int> v = {1, 2, 3, 4}; A a {1.1, 1}; B b {2, 2.2}; return 0;}变长参数模板(typename... Args)c++11提供了变长参数模板,堪比黑魔法。能够实现任意类型、任意个数的变长参数模板类和函数。能够应用经典的递归模板函数的形式去取出变长参数模板函数中的参数,示例代码如下。#include <iostream>template<typename T>void printf(T value) { std::cout << value << std::endl;}template<typename T, typename... Args>void printf(T value, Args... args) { std::cout << value << std::endl; printf(args...);}int main() { printf(1, 2, "123", 1.1); return 0;}c++14提供了更简便的办法,能够应用初始化列表开展变长参数,示例代码如下。// 编译这个代码须要开启 -std=c++14#include <iostream>template<typename T, typename... Args>auto print(T value, Args... args) { std::cout << value << std::endl; return std::initializer_list<T>{([&] { std::cout << args << std::endl; }(), value)...};}int main() { print(1, 2.1, "123"); return 0;}强类型枚举(enum class)c++11提供了类型平安的枚举类enum class。枚举类中定义的枚举值不可能被隐式转换为整数,也不能与整数间接比拟,更不能与不同的枚举类型的枚举值比拟。枚举类定义的枚举值能够定义雷同的值。枚举类中能够本人定义枚举值的类型,默认是int。能够通过重载<<运算符来实现间接打印枚举类的值。能够定义模板转换函数来不便将枚举类的枚举值与根本数据类型(如int)间接进行比拟。所有示例代码如下。#include <iostream>enum class new_enum : unsigned int { value1, value2, value3 = 888, value4 = 888};template<typename T>std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e) { return stream << static_cast<typename std::underlying_type<T>::type>(e);}template<typename T>auto to_underlying_type(const T& e) { return static_cast<typename std::underlying_type<T>::type>(e);}int main() { if (new_enum::value3 == new_enum::value4 && 888 == to_underlying_type(new_enum::value3)) { std::cout << new_enum::value3 << std::endl; } return 0;}函数对象包装器(std::function)c++11提供了能够定义任意可调用类型的函数对象包装器(std::function),这是对函数对象的一种类型平安的包装。利用std::function和c++11提供的更弱小的using语法以及Lambda函数,咱们能够更不便的实现类对象中的简略的回调函数。示例代码如下。#include <iostream>#include <memory>class A {public: using CallBack = std::function<void()>; void SetCallBack(CallBack cb) { call_back_ = cb; } void CallCallBack() { if (call_back_) { call_back_(); } }private: CallBack call_back_ = nullptr;};class B {public: B() { a = std::make_shared<A>(); a->SetCallBack([](){ std::cout << "call A cb in B" << std::endl; }); a->CallCallBack(); }private: std::shared_ptr<A> a = nullptr;};int main() { B b;}如果回调函数很简单,不适宜用Lambda函数实现,也能够通过std::bind来将回调函数绑定到类的成员函数上。智能指针初始化(make_unique)为了简化c++的指针治理,c++11扩大了规范库,推出了智能指针——std::shared_ptr/std::unique_ptr/std::weak_ptr。智能指针应用援用计数的形式来实现主动开释资源,使得c++语言更具现代性。规范库提供了std::make_shared来初始化一个std::shared_ptr,防止了咱们应用new来初始化std::shared_ptr。然而因为“被规范委员会遗记了”,规范库却没有提供make_unique的办法来给咱们初始化一个std::unique_ptr(好在c++14提供了)。为此咱们能够本人实现一个make_unique,代码如下。#include <memory>template<typename T, typename ...Args>std::unique_ptr<T> make_unique( Args&& ...args ) { return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );}int main() { std::unique_ptr<int> p = make_unique<int>(1); return 0;}

November 15, 2020 · 2 min · jiezi

关于c++:十年开发的C工程师给大家全面总结知识点指针

一、绪论指针也就是内存地址,指针变量是用来寄存内存地址的变量,不同类型的指针变量所占用的存储单元长度是雷同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针当前,不仅能够对数据自身,也能够对存储数据的变量地址进行操作。 指针绝对于一个内存单元来说,指的是单元的地址,该单元的内容外面寄存的是数据。在C语言中,容许用指针变量来寄存指针,因而,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。 二、指针的定义与应用变量的指针与指针变量:在C语言中,容许用一个变量来寄存指针,这种变量称为指针变量。指针变量的值就是某份数据的地址,这样的一份数据能够是数组、字符串、函数,也能够是另外的一个一般变量或指针变量。变量的指针就是变量的存储地址,指针变量就是存储指针的变量。指针变量是寄存一个变量地址的变量,不同于其余类型变量,它是专门用来寄存内存地址的,也称为地址变量。定义指针变量的个别模式为:类型说明符 变量名 类型说明符示意指针变量所指向变量的数据类型; 示意这是一个指针变量;变量名示意定义的指针变量名,其值是一个地址,例如:char p1;示意p1是一个指针变量,它的值是某个字符变量的地址: //定义指针变量与定义一般变量十分相似,不过要在变量名后面加星号*,格局为:int fp;//示意这是一个指针变量,fp是一个指向int数据类型的指针float a,b; //示意a和b都是指针变量,都指向一个为float数据类型的指针指针变量的应用:取地址运算符&:单目运算符&是用来取操作对象的地址。 例:&i 为取变量 i 的地址。对于常量表达式、寄存器变量不能取地址(因为它们存储在存储器中,没有地址)。 指针运算符 (间接寻址符):与&为逆运算,作用是通过操作对象的地址,获取存储的内容。例:x = &i x 为 i 的地址,x 则为通过 i 的地址,获取 i 的内容。 //赋值int a = 100;//定义了一个a的整形变量int *p_a = &a;//将一个int类型的指针p_a,p_a指向了a(也叫p_a指向了a的地址)在定义指针变量 p_a 的同时对它进行初始化,并将变量 a 的地址赋予它,此时 p_a 就指向了 a。值得注意的是,p_a 须要的一个地址,a 后面必须要加取地址符&,否则是不对的。 和一般变量一样,指针变量也能够被屡次写入,只有你想,随时都可能扭转指针变量的值: //定义一般变量float a = 99.5, b = 10.6;char c = '@', d = '#';//定义指针变量float *p1 = &a;//P1指向a的地址char *p2 = &c;//p2指向c的地址//批改指针变量的值p1 = &b;//将p1扭转指向为bp2 = &d;//将p2扭转指向为a 是一个特殊符号,表明一个变量是指针变量,定义 p1、p2 时必须带 。而给 p1、p2 赋值时,因为曾经晓得了它是一个指针变量,就没必要多此一举再带上 ,后边能够像应用一般变量一样来应用指针变量。也就是说,定义指针变量时必须带 *,给指针变量赋值时不能带。 ...

November 14, 2020 · 6 min · jiezi

关于c++:c中的引用和个人的一些学习思考

对于援用的第一个小问题在c++ primer第五版中文版中,说了这么一句:援用在初始化的时候必须绑定一个对象,且不可重现绑定,然而如果你输出以下代码 int i = 0, j =0; int &r = i; r = j;你会发现,竟然没有报错! 难道是书上错了吗? 依照我的了解,书上并没有错,r = j,实际上不是从新绑定,而是把j的值赋给了r绑定的i下来。 援用的第二个小问题还是在c++ primer中文版第五版中,指出援用自身并不是一个对象,所以不能够应用指针指向它。 而后我写出了如下代码 int i = 0; int &r = i; int *p = &r;竟然又没有报错,到底是我有问题还是书有问题? 然而有了下面一个问题的思考,这个问题也就不难理解,应用一个指针指向一个援用,实际上指向的是这个援用绑定的对象,依照这种思路了解,下面的代码是没有任何问题的。 确定变量类型的小技巧咱们经常会遇到很简单的类型,例如 const int *p;int const *p;int * const p;const int * const int p;遇到这种比拟长的变量类型申明时,咱们能够采取从右向左读的方法,例如 cont int *p就是一个指向const int类型的指针,而int * const p就是一个常量指针,指向一个int类型的数据

November 14, 2020 · 1 min · jiezi

关于c++:看完这一百个视频让你成为腾讯T9级别技术专家附学习大纲

给大家总结了一些不错的技术视频以及大场面试教训分享,心愿能在学习后端开发的路上给大家一些帮忙,有趣味的敌人能够进群973961276来一起聊聊技术吹吹水,文末附有整套课程纲要,须要的敌人可自取,课程链接在这>>腾讯T9级别技术顾问养成 一、大厂面试教训分享1、清华学员秋招面经分享会——美团字节offer在手(上) 2、普本如何在校招怀才不遇拿B站offer? 3、普本如何校招进阿里云就拿23k13薪?(上) 4、30天拿下高薪offer涨薪10W 5、非科班学员斩获京东校招 28woffer 6、秋招斩获字节&快手offer过程分享(上) 7、学长教你毕业半年如何搞定华为面试官(下) 8、学员亲身经历分享,腾讯offer的获取之路 二、高赞公开课1、详解线程池的组成与用处,带你徒手实现线程池 (上) 2、服务器通信协议设计与思考 (上) 3、百万并发级别的IM通信协议设计 4、深刻了解websocket,为你的我的项目多条思路 5、手撕万人在线游戏服务器(上) 6、面试中,红黑树在Linux内核中的3种应用 7、如何让你的程序性能飞升 8、高并发我的项目中redis的利用 9、事件驱动编程之美 10、程序员不晓得这些套路,看遍源码也枉然 11、高并发定时器实现(上) 12、redis、nginx及skynet源码剖析探索(上) 13、服务端网络解决,Redis到Memcached,再到Nginx 14、手撕万人在线游戏服务器(下) 15、从“惊群”问题来看, 高并发锁计划 16、不会吧不会吧,不会还有人搞不清线程锁、过程锁以及分布式锁吧(上) 17、网站被攻打了,nginx是不是该背这个锅 18、网络服务器模型,redis,nginx比照 19、一起来聊聊即时通讯架构技术选项(上) 20、C.C++《服务器设计模型》(上) 三、linux入门1、【linux入门】第01讲,linux环境编程我的项目精讲 2、【linux入门】第02讲,Linux开发环境ssh与Samba配置 3、【linux入门】第03讲,Linux开发环境Gcc配置 4、【linux入门】第04讲,Linux的命令操作(8条目录操作与5条文件操作) 5、【linux入门】第05讲, Shell脚本编程案例 6、【linux入门】第06讲,状态机实现文件单词统计 7、【linux入门】第07讲,通讯录实现的架构设计与需要剖析 8、【linux入门】第08讲,链表的实现与数据结构的定义 9、【linux入门】第09讲,架构接口层的实现 10、【linux入门】第10讲,业务逻辑的剖析与实现 11、【linux入门】第11讲,通讯录人员操作代码的调试 12、【linux入门】第12讲,通讯录人员操作代码调试与运行 四、音视频开发1、【FFMPEG】第01讲,windows命令行环境搭建 2、【FFMPEG】第02讲,如何查问命令帮忙文档 3、【FFMPEG】第03讲,音视频解决流程 4、【FFMPEG】第04讲,命令分类查问 5、【FFMPEG】第05讲,ffplay播放管制 五、Git1、Windows如何装置Git 2、linux如何装置Git 3、版本治理之git神器-创立仓库和搭建git服务器 4、配置git 先写到这吧,如果有人看前面再更,等不及的敌人能够进群获取所有公开课录播和大厂面试题及面经,如果能点个赞关注一下就再好不过了! 想残缺学习整套课程的敌人能够理解一下感恩回馈,福利返场流动                                                                       ...

November 14, 2020 · 1 min · jiezi

关于c++:Nginx到底能做什么这篇文章带你全面了解

前言本文只针对Nginx在不加载第三方模块的状况能解决哪些事件,因为第三方模块太多所以也介绍不完,当然本文自身也可能介绍的不残缺,毕竟只是我集体应用过和理解到过得。所以还请见谅,同时欢送留言交换 Nginx能做什么1、反向代理 2、[负载平衡] 3、HTTP服务器(蕴含动静拆散) 4、正向代理 以上就是我理解到的Nginx在不依赖第三方模块能解决的事件,上面具体阐明每种性能怎么做【文章福利】小编举荐本人的linuxC/C++语言交换群:832218493!整顿了一些集体感觉比拟好的学习书籍、视频材料共享在群文件外面,有须要的能够自行添加哦!~ 反向代理反向代理应该是Nginx做的最多的一件事了,什么是反向代理呢,以下是百度百科的说法:反向代理(Reverse Proxy)形式是指以代理服务器来承受internet上的连贯申请,而后将申请转发给外部网络上的服务器,并将从服务器上失去的后果返回给internet上申请连贯的客户端,此时代理服务器对外就体现为一个反向代理服务器。简略来说就是实在的服务器不能间接被内部网络拜访,所以须要一台代理服务器,而代理服务器能被内部网络拜访的同时又跟实在服务器在同一个网络环境,当然也可能是同一台服务器,端口不同而已。 上面贴上一段简略的实现反向代理的代码 server { listen 80; server_name localhost; client_max_body_size 1024M; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host:$server_port; }}保留配置文件后启动Nginx,这样当咱们拜访localhost的时候,就相当于拜访localhost:8080了 负载平衡负载平衡也是Nginx罕用的一个性能,负载平衡其意思就是摊派到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业要害应用服务器和其它要害工作服务器等,从而共同完成工作工作。简略而言就是当有2台或以上服务器时,依据规定随机的将申请散发到指定的服务器上解决,负载平衡配置个别都须要同时配置反向代理,通过反向代理跳转到负载平衡。而Nginx目前反对自带3种负载平衡策略,还有2种罕用的第三方策略。 1、RR(默认)每个申请按工夫程序逐个调配到不同的后端服务器,如果后端服务器down掉,能主动剔除。 简略配置 upstream test { server localhost:8080; server localhost:8081;}server { listen 81; server_name localhost; client_max_body_size 1024M; location / { proxy_pass http://test; proxy_set_header Host $host:$server_port; }}负载平衡的外围代码为 upstream test { server localhost:8080; server localhost:8081;}这里我配置了2台服务器,当然实际上是一台,只是端口不一样而已,而8081的服务器是不存在的,也就是说拜访不到,然而咱们拜访http://localhost 的时候,也不会有问题,会默认跳转到http://localhost:8080 具体是因为Nginx会主动判断服务器的状态,如果服务器处于不能拜访(服务器挂了),就不会跳转到这台服务器,所以也防止了一台服务器挂了影响应用的状况,因为Nginx默认是RR策略,所以咱们不须要其余更多的设置。 2、权重指定轮询几率,weight和拜访比率成正比,用于后端服务器性能不均的状况。 例如 upstream test { server localhost:8080 weight=9; server localhost:8081 weight=1;}那么10次个别只会有1次会拜访到8081,而有9次会拜访到8080 ...

November 14, 2020 · 1 min · jiezi

关于c++:未来的学习目标CCLinux服务器开发高级架构

前言:十大专栏技术点,每一个技术点都有书籍举荐,技术点原理+我的项目相结合解说,实现与我的项目的字眼,都是纯手写代码去实现。 一:精进基石专栏技术点:1.1、数据架构与算法(手写:排序与KMP、红黑树、B树与B+树、Hash与布隆过滤器)1.2、设计模式(责任链模式、过滤器模式、公布订阅者模式、工厂模式、代理模式)1.3、工程治理(手写: Makefile/ cmake/ conf igure、操作: git/svn与继续集成、Linux:零碎运行时参数命令) 二:高性能网络设计专栏技术点:2.1、代码的实现(网络io与select, poll,epoll、 reactor的原理与实现、 http/https服 务器的实现、 websocket协定与服务器实现)2.2、计划剖析(服务器百万并发实现、redis| memcached,|nginx网络 组件、posix API与网络协议栈udp的牢靠传输,QUIC, KCP) 三:根底组件实现专栏技术点:3.1 池式组件(手写线程池与性能剖析、ringbuffer与内存池实现、异步申请池http/mysq1/redis/dns、mysqI连接池的实现、 redis连接池的实现)3.2高性能组件(原子操作CAS、音讯队列与无锁实现、定时器计划红黑树工夫轮最小堆、锁实现原理实现、服务器连贯保活设计、try/catch组件的实现)3.2开源组件( libevent/libev框 架实战的那些坑、:异步日志计划log4cpp、应用层协定设计ProtoBuf/Thr ift、OpenssI 对称加密与非对称加密、Json數据解析/Xml解析器和工具包、字符编码Unicode原理及编程实际) 四:自研框架专栏技术点:4.1协程框架实现NtyCo(协程的设计原理与工程案例、协程的调度器实现与性能测试)4.2用户态协定栈NtyTCP(TCP/IP设计与EpolI的实现、TCP/IP定时器与滑动窗口的实现、滑动窗口/拥塞慢启动) 五:中间件开发专栏技术点:5.1 MySQL(SQL语句,索引,存储过程,触发器、数据库连接池与SQL协定分析、存储引擎原理MyISAM 与InnoDb、本人入手实现一个存储引擎、MySQ1集群计划与Rep licat ion原理)5.2 Redis(Redis相干命令与长久化、Redis连接池与协定实现、源码剖析:存储原理与数据模型、源码剖析:主从同步与原子模型、集群计划主从复制/哨兵/集群)5.3 Nginx( Nginx反向代理与零碎参数配置conf原理、广告内容推送Nginx过滤模块的实现、拜访频率统计Nginx handler 模块的实现、Nginx http状态机流程、过程间通信与Slab共享机制)5.4 MongoDB(接口编程与文档操作、集群计划与长久化备份)5.5 dfs(内核级反对的分布式存储Ceph 、分布式小文件存储fastdfs) 六:根底开源框架专栏技术点:6.1 Skynet(手撕Skynet高性能网关、 actor 实现与cluster集群/负载平衡、skynet网络模块 热更新数据共享)6.2 ZeroMQ(ZeroMQ Router-Dealer模式实现、音讯模型与工程案例、网络机制与性能剖析)6.3 DPDK(PCI原理与testpmd/ 13fwd/ske leton、kni数据流程与协定栈解析、DNS协定解析与服务器实现、高性能Nginx网关实现、半虛拟化virtio与vhost减速)。相干视频:Linux服务器开发-阿里云用DPDK如何解决千万级流量并发(上)Linux服务器开发-阿里云用DPDK如何解决千万级流量并发(中)Linux服务器开发-阿里云用DPDK如何解决千万级流量并发(下) 七:Linux内核源码专栏技术点:7.1过程治理(过程治理和调度、锁与过程间通信、零碎调用与自定义syscall的实现)7.2内存治理(物理内存治理、过程虚拟内存mm_ struct剖析、页面回收和页替换)7.3文件系统(虚构文件系统、Ext文件系统族、无长久存储的文件系统、扩大属性和访问控制表)7.4设施驱动(内核编译与虚拟机系统升级、过程间通信组件实现、虚构网络适配器的实现) 八:性能剖析专栏技术点:8.1性能工具(高性能代码构建零碎tundra、Http压测工具WRK、网站压测工具webbench)8.2调试库(内存调试性能剖析工具Valgrind、谷歌C++测试框架Goog leTest、内存调配跟踪库MemTrack)8.3内核跟踪(内核探测SystemTap、热图剖析与生成) 九:分布式架构专栏技术点:9.1 架构实战(腾讯微服务RPC框架Tars、虚拟化Docker与容器编排)9.2架构原理(分布式注册服务中心etcd、快播核心技术揭秘P2P框架的实现) 十:我的项目实战专栏技术点:10.1 互联网并发云盘(我的项目需要剖析与我的项目架构介绍、高负载Nginx搭建/FastCGI接口、分布式FastDFS存储集群部署、文件接口设计与JSON协定、产品上云公网公布/测试用例)10.2微服务即时通讯(IM实时流媒体/架构设计接口阐明、IM音讯服务器/文件传输服务器、文件存储服务器/路由服务器、登陆服务器/HTTP服务器、用户注册测试用例/内存治理测试用例、产品上云公网公布/公网测试上线) 十一:配套参考书籍材料举荐学习材料收费分享;看这里首先祝贺您,可能认真的浏览到这里,如果对局部了解不太明确,倡议先将文章珍藏起来,而后对不分明的知识点进行查阅,而后在进行浏览,相应你会有更深的认知。如果您喜爱这篇文章,就点个赞或者【关注我】吧!!

November 14, 2020 · 1 min · jiezi

关于c++:CC-assert函数用法总结

1. 简介assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回谬误,则终止程序执行。 原型定义: #include <assert.h>void assert( int expression ); assert的作用是先计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,而后通过调用 abort 来终止程序运行。请看上面的程序清单badptr.c: #include <stdio.h>#include <assert.h>#include <stdlib.h>int main( void ){ FILE *fp; fp = fopen( "test.txt", "w" );//以可写的形式关上一个文件,如果不存在就创立一个同名文件 assert( fp ); //所以这里不会出错 fclose( fp ); fp = fopen( "noexitfile.txt", "r" );//以只读的形式关上一个文件,如果不存在就关上文件失败 assert( fp ); //所以这里出错 fclose( fp ); //程序永远都执行不到这里来 return 0;} [root@localhost error_process]# gcc badptr.c        [root@localhost error_process]# ./a.out        a.out: badptr.c:14: main: Assertion `fp' failed. ...

November 14, 2020 · 1 min · jiezi

关于c++:聊聊IO多路复用之selectpollepoll详解

IO多路复用是指内核一旦发现过程指定的一个或者多个IO条件筹备读取,它就告诉该过程。IO多路复用实用如下场合: 当客户解决多个描述符时(个别是交互式输出和网络套接口),必须应用I/O复用。当一个客户同时解决多个套接口时,而这种状况是可能的,但很少呈现。如果一个TCP服务器既要解决监听套接口,又要解决已连贯套接口,个别也要用到I/O复用。如果一个服务器即要解决TCP,又要解决UDP,个别要应用I/O复用。如果一个服务器要解决多个服务或多个协定,个别要应用I/O复用。与多过程和多线程技术相比,I/O多路复用技术的最大劣势是零碎开销小,零碎不用创立过程/线程,也不用保护这些过程/线程,从而大大减小了零碎的开销。 目前反对I/O多路复用的零碎调用有 select,pselect,poll,epoll,I/O多路复用就是通过一种机制,一个过程能够监督多个描述符,一旦某个描述符就绪(个别是读就绪或者写就绪),可能告诉程序进行相应的读写操作。但select,pselect,poll,epoll实质上都是同步I/O,因为他们都须要在读写事件就绪后本人负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需本人负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。 对于IO多路复用机制不了解的同学,能够后行参考《聊聊Linux 五种IO模型》,来理解Linux五种IO模型。 1 select、poll、epoll简介# epoll跟select都能提供多路I/O复用的解决方案。在当初的Linux内核里有都可能反对,其中epoll是Linux所特有,而select则应该是POSIX所规定,个别操作系统均有实现。 1.1 select## 基本原理: select 函数监督的文件描述符分3类,别离是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述符就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立刻返回设为null即可),函数返回。当select函数返回后,能够通过遍历fdset,来找到就绪的描述符。 根本流程,如图所示: 输出图片说明 select目前简直在所有的平台上反对,其良好跨平台反对也是它的一个长处。select的一个毛病在于单个过程可能监督的文件描述符的数量存在最大限度,在Linux上个别为1024,能够通过批改宏定义甚至从新编译内核的形式晋升这一限度,然而这样也会造成效率的升高。 select实质上是通过设置或者查看寄存fd标记位的数据结构来进行下一步解决。这样所带来的毛病是: select最大的缺点就是单个过程所关上的FD是有肯定限度的,它由FD_SETSIZE设置,默认值是1024。一般来说这个数目和零碎内存关系很大,具体数目能够cat /proc/sys/fs/file-max观察。32位机默认是1024个。64位机默认是2048.【文章福利】小编举荐本人的linuxC/C++语言交换群:832218493!整顿了一些集体感觉比拟好的学习书籍、视频材料共享在群文件外面,有须要的能够自行添加哦!~ 对socket进行扫描时是线性扫描,即采纳轮询的办法,效率较低。当套接字比拟多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来实现调度,不论哪个Socket是沉闷的,都遍历一遍。这会节约很多CPU工夫。如果能给套接字注册某个回调函数,当他们沉闷时,主动实现相干操作,那就防止了轮询,这正是epoll与kqueue做的。 须要保护一个用来寄存大量fd的数据结构,这样会使得用户空间和内核空间在传递该构造时复制开销大。1.2 poll## 基本原理: poll实质上和select没有区别,它将用户传入的数组拷贝到内核空间,而后查问每个fd对应的设施状态,如果设施就绪则在设施期待队列中退出一项并持续遍历,如果遍历完所有fd后没有发现就绪设施,则挂起以后过程,直到设施就绪或者被动超时,被唤醒后它又要再次遍历fd。这个过程经验了屡次无谓的遍历。 它没有最大连接数的限度,起因是它是基于链表来存储的,然而同样有一个毛病: 大量的fd的数组被整体复制于用户态和内核地址空间之间,而不论这样的复制是不是有意义。poll还有一个特点是“程度触发”,如果报告了fd后,没有被解决,那么下次poll时会再次报告该fd。留神: 从下面看,select和poll都须要在返回后,通过遍历文件描述符来获取曾经就绪的socket。事实上,同时连贯的大量客户端在一时刻可能只有很少的处于就绪状态,因而随着监督的描述符数量的增长,其效率也会线性降落。 1.3 epoll## epoll是在2.6内核中提出的,是之前的select和poll的加强版本。绝对于select和poll来说,epoll更加灵便,没有描述符限度。epoll应用一个文件描述符治理多个描述符,将用户关系的文件描述符的事件寄存到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。 基本原理: epoll反对程度触发和边缘触发,最大的特点在于边缘触发,它只通知过程哪些fd刚刚变为就绪态,并且只会告诉一次。还有一个特点是,epoll应用“事件”的就绪告诉形式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采纳相似callback的回调机制来激活该fd,epoll_wait便能够收到告诉。 epoll的长处: 没有最大并发连贯的限度,能关上的FD的下限远大于1024(1G的内存上能监听约10万个端口)。效率晋升,不是轮询的形式,不会随着FD数目的减少效率降落。只有沉闷可用的FD才会调用callback函数;即Epoll最大的长处就在于它只管你“沉闷”的连贯,而跟连贯总数无关,因而在理论的网络环境中,Epoll的效率就会远远高于select和poll。内存拷贝,利用mmap()文件映射内存减速与内核空间的消息传递;即epoll应用mmap缩小复制开销。epoll对文件描述符的操作有两种模式:LT(level trigger)和ET(edge trigger)。LT模式是默认模式,LT模式与ET模式的区别如下: LT模式:当epoll_wait检测到描述符事件产生并将此事件告诉应用程序,应用程序能够不立刻解决该事件。下次调用epoll_wait时,会再次响应应用程序并告诉此事件。 ET模式:当epoll_wait检测到描述符事件产生并将此事件告诉应用程序,应用程序必须立刻解决该事件。如果不解决,下次调用epoll_wait时,不会再次响应应用程序并告诉此事件。 LT模式LT(level triggered)是缺省的工作形式,并且同时反对block和no-block socket。在这种做法中,内核通知你一个文件描述符是否就绪了,而后你能够对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会持续告诉你的。 ET模式ET(edge-triggered)是高速工作形式,只反对no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll通知你。而后它会假如你晓得文件描述符曾经就绪,并且不会再为那个文件描述符发送更多的就绪告诉,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比方,你在发送,接管或者接管申请,或者发送接管的数据少于一定量时导致了一个EWOULDBLOCK 谬误)。然而请留神,如果始终不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的告诉(only once)。 ET模式在很大水平上缩小了epoll事件被反复触发的次数,因而效率要比LT模式高。epoll工作在ET模式的时候,必须应用非阻塞套接口,以防止因为一个文件句柄的阻塞读/阻塞写操作把解决多个文件描述符的工作饿死。 在select/poll中,过程只有在调用肯定的办法后,内核才对所有监督的文件描述符进行扫描,而epoll当时通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采纳相似callback的回调机制,迅速激活这个文件描述符,当过程调用epoll_wait()时便失去告诉。(此处去掉了遍历文件描述符,而是通过监听回调的的机制。这正是epoll的魅力所在。)留神: 如果没有大量的idle-connection或者dead-connection,epoll的效率并不会比select/poll高很多,然而当遇到大量的idle-connection,就会发现epoll的效率大大高于select/poll。 2 select、poll、epoll区别# 反对一个过程所能关上的最大连接数 输出图片说明 FD剧增后带来的IO效率问题 输出图片说明 消息传递形式 输出图片说明 综上,在抉择select,poll,epoll时要依据具体的应用场合以及这三种形式的本身特点: 外表上看epoll的性能最好,然而在连接数少并且连贯都非常沉闷的状况下,select和poll的性能可能比epoll好,毕竟epoll的告诉机制须要很多函数回调。select低效是因为每次它都须要轮询。但低效也是绝对的,视状况而定,也可通过良好的设计改善。

November 13, 2020 · 1 min · jiezi

关于c++:初学小白CC语言知识难点题目总结代码演示

一、给定一个字符串,返回它的最长回文子串。如果存在多个答案,返回任意一个即可。字符串长度 ≤≤ 1000。算法:(暴力枚举)O(n2)O(n2) 因为字符串长度小于1000,因而咱们能够用 O(n2)O(n2) 的算法枚举所有可能的状况。 首先枚举回文串的核心 ii,而后分两种状况向两边扩大边界,直到遇到不同字符为止: 回文串长度是奇数,则顺次判断 s[i−k]==s[i+k],k=1,2,3,…s[i−k]==s[i+k],k=1,2,3,…回文串长度是偶数,则顺次判断 s[i−k]==s[i+k−1],k=1,2,3,…s[i−k]==s[i+k−1],k=1,2,3…如果遇到不同字符,则咱们就找到了以 ii 为核心的回文串边界。 工夫复杂度剖析:一共两重循环,所以工夫复杂度是 O(n2)O(n2)。 C++代码演示: class Solution {public: string longestPalindrome(string s) { int res = 0; string str; for (int i = 0; i < s.size(); i ++ ) { for (int j = 0; i - j >= 0 && i + j < s.size(); j ++ ) if (s[i - j] == s[i + j]) { if (j * 2 + 1 > res) { res = j * 2 + 1; str = s.substr(i - j, j * 2 + 1); } } else break; for (int j = i, k = i + 1; j >= 0 && k < s.size(); j -- , k ++ ) if (s[j] == s[k]) { if (k - j + 1 > res) { res = k - j + 1; str = s.substr(j, k - j + 1); } } else break; } return str; }};二、给定一个整型数组,要求返回两个数的下标,使得两数之和等于给定的目标值,要求同一个下标不能应用两次,数据保障有且仅有一组解。算法:(暴力枚举) O(n2)O(n2) ...

November 12, 2020 · 4 min · jiezi

关于c++:你和腾讯资深架构师之间差的不仅仅是年龄进阶必看

导读:浏览本文须要有足够的工夫,笔者会由浅到深带你一步一步理解一个资深架构师所要把握的各类知识点,你也能够依照文章中所列的常识体系比照本身,对本人进行查漏补缺,感觉本文对你有帮忙的话,能够点赞关注一下。 目录: 一、精进基石篇 二、高性能网络设计篇 三、根底组件实现专栏篇 四、自研框架篇 五、根底开源框架篇 六、中间件开发篇 七、Linux内核篇 八、性能剖析篇 九、分布式架构篇 十、微服务即时通讯篇 十一、举荐书籍 十二、总结 想要理解更多C/C++Linux技术的,能够关注我一下,我后续也会整顿更多对于架构技术这一块的知识点分享进去,另外顺便给大家举荐一个交流学习群:832218493,外面会分享一些资深架构师录制的视频录像:内容包含C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等等多个知识点高级进阶干货学习。还能支付收费的学习资源,目前受害良多,以下的课程体系图也是在群里获取。 一、精进基石篇 1.1 数据结构与算法 排序 (11种排序) 与 KMP红黑树 证实B树与B+树Hash与布隆过滤器1.2 设计模式 23种 责任链模式过滤器模式公布订阅模式工厂模式 等等1.3 工程治理 Makefile/cmake/configuregit /svn与继续集成Linux零碎运行时命令二、高性能网络设计篇 2.1. 代码实现 网络io与select/poll/epollreactor的原理与实现http/https web服务器的实现websocket协定与服务器实现2.2 计划剖析 服务器百万并发的实现(c10K,c1000k, C10M)redis/memcached/Nginx网络组件Posix API与网络协议栈UDP牢靠协定 QUIC/KCP 三、根底组件实现专栏篇 3.1 池式构造 线程池(手写)内存池 ringbuffer异步申请池 性能优化,异步mysql 异步dns 异步redismysql连接池redis连接池高性能组件原子操作 CAS音讯队列与无锁队列定时器的计划 红黑树 工夫轮 最小堆锁的实现原理 互斥锁,自旋锁 ,乐观锁,乐观锁,分布式锁服务器连贯保活 keepalivedtry/catch的实现3.3 开源组件 libevent/libev框架异步日志计划 log4cpp应用层协定 protobuf/thriftopenssl加密json与xml解析器字符编码unicode/gbk/utf- 四、自研框架篇 4.1 协程框架的实现 NtyCo 协程的原理与工程案例协程的调度器实现4.2 用户态协定栈 NtyTCP (tcp/ip) ...

November 12, 2020 · 1 min · jiezi

关于c++:30道最新Linux内核大厂面试题含答案

Linux 中次要有哪几种内核锁?===================== Linux 的同步机制从 2.0 到 2.6 以来一直倒退欠缺。从最后的原子操作,到起初 的信号量,从大内核锁到明天的自旋锁。这些同步机制的倒退随同 Linux 从单处 理器到对称多处理器的过渡;随同着从非抢占内核到抢占内核的适度。Linux 的 锁机制越来越无效,也越来越简单。 自旋锁最多只能被一个可执行线程持有,如果一个执行线程试图申请一个已被争 用曾经被持有)的自旋锁,那么这个线程就会始终进行忙循环——旋转——期待 锁从新可用。要是锁未被争用,申请它的执行线程便能立即失去它并且持续进行。 自旋锁能够在任何时刻避免多于一个的执行线程同时进入临界区。 信号量的睡眠个性,使得信号量实用于锁会被长时间持有的状况;只能在过程上 下文中应用,因为中断上下文中是不能被调度的;另外当代码持有信号量时,不 能够再持有自旋锁。 Linux 内核中的同步机制:原子操作、信号量、读写信号量和自旋锁的 API,另 外一些同步机制,包含大内核锁、读写锁、大读者锁、RCU (Read-Copy Update, 顾名思义就是读-拷贝批改),和程序锁。 linux内核视频解说:linux内核文件系统具体实现与内核裁剪,含30道linux面试题 Linux 中的用户模式和内核模式是什么含意?=========================== MS-DOS 等操作系统在繁多的 CPU 模式下运行,然而一些类 Unix 的操作系统则使 用了双模式,能够无效地实现工夫共享。在 Linux 机器上,CPU 要么处于受信赖 的内核模式,要么处于受限制的用户模式。除了内核自身处于内核模式以外,所 有的用户过程都运行在用户模式之中。 内核模式的代码能够无限度地拜访所有处理器指令集以及全副内存和 I/O 空间。 如果用户模式的过程要享有此特权,它必须通过零碎调用向设施驱动程序或其余 内核模式的代码发出请求。另外,用户模式的代码容许产生缺页,而内核模式的 代码则不容许。 在 2.4 和更早的内核中,仅仅用户模式的过程能够被上下文切换出局,由其余进 程抢占。除非产生以下两种状况,否则内核模式代码能够始终独占 CPU: (1) 它被迫放弃 CPU; (2) 产生中断或异样。 2.6 内核引入了内核抢占,大多数内核模式的代码也能够被抢占。 怎么申请大块内核内存?=============== 在 Linux 内核环境下,申请大块内存的成功率随着零碎运行工夫的减少而缩小, 尽管能够通过 vmalloc 系列调用申请物理不间断但虚拟地址间断的内存,但毕竟 其应用效率不高且在 32 位零碎上 vmalloc 的内存地址空间无限。所以,个别的 倡议是在系统启动阶段申请大块内存,然而其胜利的概率也只是比拟高而已,而 不是 100%。如果程序真的比拟在意这个申请的胜利与否,只能退用“启动内 存”Boot Memory)。上面就是申请并导出启动内存的一段示例代码: void x_bootmem = NULL; EXPORT_SYMBOL(x_bootmem); unsigned long x_bootmem_size = 0; EXPORT_SYMBOL(x_bootmem_size); static int __init x_bootmem_setup(char str) { x_bootmem_size = memparse(str, &str); x_bootmem = alloc_bootmem(x_bootmem_size); printk("Reserved %lu bytes from %p for xn", x_bootmem_size, x_bootmem); return 1; } __setup("x-bootmem=", x_bootmem_setup); 可见其利用还是比较简单的,不过利弊总是共生的,它不可避免也有其本身的限 制: 内存申请代码只能连贯进内核,不能在模块中应用。被申请的内存不会被页调配 器和 slab 分配器所应用和统计,也就是说它处于零碎的可见内存之外,即便在 未来的某个中央你开释了它。个别用户只会申请一大块内存,如果须要在其上实 现简单的内存治理则须要本人实现。在不容许内存调配失败的场合,通过启动内 存预留内存空间将是咱们惟一的抉择。 ...

November 12, 2020 · 3 min · jiezi

关于c++:C表达式

表达式是_运算符_和它们的_操作数_的序列,它指定一项计算。 表达式的求值能够产生一个后果(比方 2+2 的求值产生后果 4),也可能产生副作用(比方对 std::printf("%d",4) 的求值在规范输入上打印字符 '4')。 概述值类别(左值 (lvalue)、右值 (rvalue)、泛左值 (glvalue)、纯右值 (prvalue)、亡值 (xvalue))是依据表达式的值所进行的分类实参和子表达式的求值程序指定取得两头后果所用的程序运算符常见运算符 赋值 [自增自减](https://www.apiref.com/cpp-zh... "cpp/language/operator incdec") 算术 逻辑 比拟 成员拜访 其余 a = ba += ba -= ba *= ba /= ba %= ba &= ba |= ba ^= ba <<= ba >>= b ++a--aa++a-- +a-aa + ba - ba * ba / ba % b~aa & ba | ba ^ ba << ba >> b ...

November 11, 2020 · 2 min · jiezi