特色

前端To do list

迫于生计,要从零开始学习前端。

由于之前的to do list 年代久远+ 前端的技术栈可之前几乎没有关系,因此新开一篇记录。

  • css盒子模型
  • 布局,flex
  • 前端debug的方法
  • javascript,有空可以使用js刷leetcode练习语法
  • typescript
  • jsx,以及jsx的typescript版tsx
  • 学习axios https://alligator.io/react/axios-react/
  • 学习dva: https://github.com/sorrycc/blog/issues/62
  • 学习umijs https://umijs.org/zh/guide/with-dva.html#%E7%89%B9%E6%80%A7

[C++11]std::condition_variable notes

condition_variable 类是同步原语,能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable 。

用人话来说,condition_variable,也就是条件变量,是线程间通信的一种方式。

线程之间在很多时候需要通信,比如经典的生产者消费者问题

一个比较naive的方案是,用mutex来保护一个flag,然后另一线程不停得check这个flag的状态是否改变。以及在这个方案上的改进:让另一个线程check之后,可以先睡一段时间。

但是这两种方法都不够好。第一种不好的原因当然是不停得check,肯定会耗费大量的资源。而第二种,由于没办法准确估计要休眠的时间,因此不够实际。

这个时候我们可以考虑使用条件变量。

条件变量是可以用在如下场景: 一个或者多个线程在等某个条件的成立,而这个条件由另外的线程所控制。当该条件成立时,控制该条件的线程会主动通知这些线程,将这些线程唤醒。

如下是一个最简单的例子:

接下来是一个较为复杂的例子,一个线程安全的队列的实现,

以及,虽然现在,这样线程安全的数据结构应该早就有人封装好了,我们直接使用就行了,比如之前用过的intel tbb的concurrent_queue,不过如果对内部实现一无所知,大概没办法感觉到这种精巧之处吧。。

参考资料:

std::condition_variable

std::condition_variable

以及借鉴了 c++并发编程第四章中格式化后的代码

 

 

 

 

std::call_once && std::once_flag notes

多线程保护数据时,一种较为特殊的情况是只需要保护资源的初始化。

资源初始化一般遵循”lazy initialization”的原则,也就是在用到该资源最近的地方再初始化。

比较容易想到的办法是用std::mutex,将资源初始化的地方锁起来,如下:

这确实是一个办法。但是初始化时如果需要耗费比较多的时间,当有比较多的线程时,一个线程初始化时,其他线程会耗时间在不必要的等待上。

在c++11以后,我们可以使用std::once_flag和std::call_once来解决资源初始化时加锁的问题。比起显示调用std::mutex的好处是,资源消耗更少。

 

下面是两个例子:

或者更一般地,可以解决一类在多线程环境下保证某段代码只执行一次的问题。

比如声明的一个static 变量。

参考资料:

std::call_once

once_flag

 

 

 

learn java in 21 minutes for C++ Programmers

先放资料:

Learning a New Programming Language: Java for C++ Programmers

 

java package

先说几条重要的人话:

  • 一个java文件第一行可以声明该文件所属于的package,package的名字必须与整个工作目录的路径名相同。
  • 同一个package下的class默认有互相访问的权限。
  • 访问属性设置为public的class,如果该class所在的file声明了package,那么可以被其他package下的class访问到。
  • .java的文件名必须与文件中设置为public的class名保持一致(如果没有public的类,那么名称任意)
  • Every class is part of some package.
  • All classes in a file are part of the same package.
  • You can specify the package using a package declaration:
      • package

    name

       ;

    as the first (non-comment) line in the file.

  • Multiple files can specify the same package name.
  • If no package is specified, the classes in the file go into a special unnamed package (the same unnamed package for all files).
  • If package name is specified, the file must be in a subdirectory called name (i.e., the directory name must match the package name).
  • You can access public classes in another (named) package using:package-name.class-nameYou can access the public fields and methods of such classes using:package-name.class-name.field-or-method-nameYou can avoid having to include the package-name using:
      • import

    package-name

      .*;

    or

      • import

    package-name.class-name

      ;

    at the beginning of the file (after the package declaration). The former imports all of the classes in the package, and the second imports just the named class. You must still use:class-nameto access the classes in the packages, andclass-name.field-or-method-nameto access the fields and methods of the class; the only thing you can leave off is the package name.

下面是一些例子:

Assume that you are working in a directory called Javadir, and that you create four files, whose contents are shown below.

Here are the directories and file names you must use:

  • File 1 must be in a subdirectory named ListPkg, in a file named List.java.
  • File 2 must also be in the ListPkg subdirectory, in a file named NoNextItemException.java.
  • File 3 must be in a file named Test.java (in the Javadir directory).
  • File 4 can be in any .java file (in the Javadir directory).

And here are the classes that can be accessed by the code in each file:

  • Files 1 and 2:
    • The code in the first two files (ListPkg/List.java and ListPkg/NoNextItemException.java) can access the classes defined in the same package (List, ListNode, and NoNextItemException). (No access was specified for those classes, so they get the default, package access.)
    • The code in files 1 and 2 cannot access class Test, even though it is a public class. The problem is that Test is in an unnamed package, so the code in the ListPkg package has no way to import that package, or to name class Test.
    • The code in files 1 and 2 cannot access classes Utils and Test2, because they have default (package) access, and are in a different package.
  • Files 3 and 4:
    • The code in file 3 (Test.java) can access classes ListPkg.List, ListPkg.NoNextItemException, Test, Utils, and Test2 (the first two because they are public classes in a named package, and the last three because they are in the same, unnamed package, and have either public or package access). Note however, that if the code in Test.java uses the class Test2, and that class is not in a file called Test2.java, then the file that contains class Test2 must be compiled first, or else the class will not be found.
    • The code in file 4 (the file that contains class Test2) can access the same classes as the code in file 3 (Test.java).

[c++11 ]std::move 右值引用 转移语义 完美转发 notes

起因是在看<CplusplusConcurrencyInAction_PracticalMultithreading>,里面讲到转移一个std::thread的ownership提到了std::move.

之前[C++11 ] std::ref&&std::reference_wrapper notes 提到的情况是在我们想要用引用的时候却进行了拷贝,得到不符合期望的结果。现在的情况是,有些object或许是不支持拷贝构造的。比如std::unique_str,std::ifstream,这个时候如果我们需要传参数进去,就可以使用std::move来实现。比如下面这个例子:

当然这只是使用std::move的一种情形,即传递不允许拷贝构造的object作为参数。

另外,std::move可以更有效率地传递资源。内容之后补orz

实际上std::move()的作用是传进去一个object,返回这个object的右值引用(rvalue reference)

首先区分左值和右值,这其实是一个c语言中就有的概念(作为区分,右值引用是C++11中新引入的概念)

一般来说,右值是不能被取地址的值。在C++11之前,右值是不能被引用的。

语法上为了区分C++11之前的引用(也就是左值引用&),右值引用的符号为&&

那么为什么要引入“右值引用”这个概念? 主要有两个目的:完美转发(Perfect Forwarding)转移语义(Move Sementics)

转移语义可以将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁。转移语义是和拷贝语义相对的,可以类比文件的剪切与拷贝,当我们将文件从一个目录拷贝到另一个目录时,速度比剪切慢很多。

完美转发,也叫精确传递,指的是“需要将一组参数原封不动的传递给另一个函数”。

原封不动的含义是说:数值不变,左值/右值属性不变,const/non-const属性不变。

在泛型函数中,这样的需求非常普遍。

比如下面这个例子:

在右值引用出现,模板的每个参数都必须重载两个类型,总的重载次数是指数级的orz,警察听了想打人

然而有了右值引用,不管模板右多少个参数,我们只需要定义一次,接受一个右值引用的参数,就能够将所有的参数类型原封不动的传递给目标函数。

 

那么最后说回std::move. std::move的作用就是传入左值,返回右值引用,从而使用右值引用带来的好处(节省资源,实现完美转发等)

 

 

 

 

参考资料:

[C++11 ] std::ref&&std::reference_wrapper notes

起因是在看《CplusplusConcurrencyInAction_PracticalMultithreading》的时候,里面讲到初始化std::thread的时候,如果thread funtion的参数列表中有引用,需要传入std::ref才可以得到符合预期的结果。

查阅发现std::ref是用来生成std::reference_wrapper。 按照 cppreference 上的话来说

std::reference_wrapper 是包装引用于可复制、可赋值对象的类模板。它常用作将容器存储入无法正常保有引用的标准容器(类似 std::vector )的机制。

用人话来说,就是有的时候一些地方(比如STL容器中传值,又比如std::bind)会默认使用复制,这可能与我们想使用引用的期望不符。

具体见下面的几个例子:

我们发现直接传进去的参数n1的值没有改变,而使用std::ref传进去的值的结果符合预期。

n1的值不符合预期的原因是,在调用std::bind的时候,会先将参数复制一份,然后传入函数f时,传入的不是在main函数中定义的n1的引用,而是对n1复制了一份得到的临时变量的引用。在函数f中对n1的修改只会使得n1的复制值与其保持一致,而不会改变n1.

下面是一个关于 std::reference_wrapper 的例子

 

最后我们回到开始,将参数在通过创建std::thread传给thread funtion的时候,参数默认情况下仍然是被拷贝了一份,与上面std::bind的情况类似,因此需要使用std::ref

 

参考资料:

 

 

 

typescript学习笔记

先放参考资料:

TypeScript 入门教程

React & Webpack

react-typescript-cheatsheet (强推一波,讲了很多react+ts的实践)

typescript是javascript的语法扩展。。。好处是提供了类型。。可以在编译(结果为js文件)的时候提供静态的类型检查。。。

typescript的问号语法:标记某个参数为可选。

例子:

 

关于typescript的类型推断。。如果在定义时直接赋值则会进行推断,否则会推断类型为any.

 

当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法

类型断言:

类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的

泛型:

泛型约束:传入的模板参数必须包含接口的形状:

上面的代码表示,传入的参数必须包含一个类型为number,名字为length的属性

这里要强调的是,这里名字是重要的。如果把length改为其他名字,将不能通过编译。

 

定义一个普通的class属性(不是props)的办法:

在构造函数之前声明即可,参考如下代码中的pointer:number

 

 

 

 

react路由提高(Prompt、Redirect、match、Switch)

路由是根据不同的 url 地址展示不同的内容或页面。

前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面实现的。

不过不懂啥叫“路由提高”。。。

原因是senseRader中的前端代码里,使用了switch组件。

它的特性是我们只渲染所匹配到的第一个路由组件,一般界面渲染的时候,会渲染所有匹配到的路由组件。它的孩子节点只能是Route组件或者Redirect组件(并不懂啥叫Route组件或者Redirect组件。。。先不管了)

 

[设计模式] 观察者( Observer )模式学习笔记

最近在学习node.js,里面讲到node.js的事件机制使用了观察者模式,因此来学习一下。

观察者模式的目的是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

因此观察者模式又叫发布-订阅模式。

下面放一个简化之后的例子:

 

update:怪不得觉得熟悉,原来Qt的信号槽机制Signals_and_slots 就是使用了观察者模式。

参考资料:

观察者模式-菜鸟教程

我所理解的设计模式(C++实现)——观察者模式(Observer Pattern)

JavaScript 学习笔记

暂时没空从头开始搞…用到哪里先记录一下好了orz

我觉得不行,还是要先大致了解一下。

参考资料:

A re-introduction to JavaScript (JS tutorial)

继承与原型链

 

 

react学习笔记

首先介绍一个fb家的快速开发react的工具 create-react-app

这个东西依赖node6.0或者更高版本。

关于在ubuntu 14.04上安装node ,可以参考这个链接

发现执行nvm install 6.0会没有任何相应…但是实际上已经安装好了。

接下来安装create-react-app

命令是: npm install –global create-react-app

然后创建一个react app

命令为:create-react-app first_react_app

挂着代理大概需要半小时左右。

或者可以使用淘宝npm镜像:

设置方法为: npm config set registry https://registry.npm.taobao.org,设置完成后,重新执行 create-react-app first-app

实现的第一个组件,功能是点击按钮增加计数…

 

JSX是JS的语法扩展。JSX中使用的元素包含html中的元素和React中的组件。React 判断一个元素是 HTML 元素还是 React 组件的原则就是看第一个字母是否大
写。

React设计上的分离是逻辑上的分离,而不是技术上的分离。如果是要实现一件事,就会把CSS,html,JS三种语言混在一起。

React的数据分为prop(property)和state两种。区别是:

  • prop 用于定义外部接口, state 用于记录内部状态;
  • prop 的赋值在外部世界使用组件时, state 的赋值在组件内部;
  • 组件不应该改变 prop 的值,而 state 存在的目的就是让组件来改变的

 

扩展属性:

 

 

 

参考资料:

react.express

React + antd怎么上传图片

[设计模式] 组合模式(composite) 学习笔记

目的是忽略单一对象和组合对象的不同。 有点像以前写过的用链表定义一个树结构,每个节点是一个val + 多个*tree 。如果某个节点是叶子节点了,那么对应的*tree都为NULL. 只不过这里用了更加面向对象的实现。

具体看代码:

 

最后打印的结果为:

root 1
Leaf A 2
Leaf B 2
Composite X 2
Leaf XA 3
Leaf XB 3
Composite XY 3
Leaf XYA 4
Leaf XYB 4

[C++11] promise && future leanrning notes

std::promise and std::future

 

用人话就是,主线程传给附属线程一个promise Object,然后主线程想要获取附属线程set给promise Object的值(也就是该线程返回的某个结果),需要通过主线程中的promise object 得到对应的future object(每个promise 对应一个 future),然后调用future 的get方法。如果附属线程没有执行作为参数传入的promise的set方法去返回结果,那么程序就会block住。

 

参考资料:

C++11 Multithreading – Part 7: Condition Variables Explained