在 Windows 上运行 Linux GUI 程序

自从 Windows 10 提供 WSL 之后,在 Windows 上运行 Linux CLI 程序并不是一个复杂的事情;然而俗话说饱暖思淫欲,既然可以做到在 Windows 上跑 Linux CLI 了,下一步自然想的是在 Windows 上跑 Linux GUI 程序。

之所以要跑 GUI 是因为,无论是 vscode 还是 CLion,写 C++ 的体验都比在 terminal 里开一个 vim 要好太多了,无论你是花了多少时间配置了 .vimrc,在 CLion 面前都是战五渣。更何况我买了 Jetbrains 的 All product license,不用用难道留着过年吗。

这里先解答两个常见疑问:

Q:为什么不直接在虚拟机里使用?
A:因为 Linux 对 4K 屏原生支持太糟糕。哪怕 Mint 提供了 double scaling,解决了一些外观上的问题,我在 4K 的环境下一开 vscode 程序就崩溃,而且运行操作明显掉帧。
另外一个问题是,单纯的虚拟机操作和外界宿主太隔离,等于我得配置两套完全一样的环境(比如浏览器,常见的应用,甚至 SS 等),而且和宿主的交互非常不够便利。

Q:为什么不买 macbook?
A:??你是认真的么?OS X 那么垃圾的系统。再说我要写 C++ server-end 的代码,要是可以用 OS X 我为什么不直接在 Windows 上跑?

另外有一个剧透:我尝试过运行 WSL 里的 Linux GUI 程序,例如 CLion,但是目前 WSL 的文件系统性能过于糟糕,CLion 一个劲的冒错误提示,所以,下面的环境假定是虚拟机里的 Linux 或者一台单独的 Linux 设备。

Monthly Read Posts in Jun 2018

Programming Language

CppCon 2015: Richard Powell “Intro to the C++ Object Model”

基本覆盖了 POD,无需函数类,单继承的情况,扫盲效果俱佳。

至于为什么没有包含 multiple inheritance / virtual inheritance,作者说自己不是很 condifent with that。

讲道理,MI / VI 在一般的设计里都会尽量避免,而且各种乱七八糟的 case 很多,这里不涉及反而是个正确的做法。


Assertions

首先,我很赞同文中作者对于 assertion 是 guarantees given by the author of a piece of code to himself/herself 但是接下来的大部观点都不赞同。

比如作者认为不应该 assert on precodintions & postconditions,因为 assertion 是 for implementation details,这个思路其实不对。

关于 assertion,目前看过最好的阐述还是 Writing Solid Code,推荐去阅读这个。


Compile-time computations

这篇 post 展示了 constexpr functions 错误报告的常见手段:抛异常。

这个在之前的某个 cppcon talk 里有专门的介绍。

另外,文中更进一步,抽出专门的 constexpr validation functions,并通过 comma operator 串联。

C++ 14 支持多句之后,连 comma operatos 都可以免掉了。


Modern CMake

但凡有点历史的东西,在演进到一个新的阶段时,总会总结一套新的 practices 然后冠之以 modern,例如 modern C++,还有今天的主题 —— modern CMake。

上周花了一点时间稍微研究了一下所谓的 modern cmake,然后将 KBase 在 POSIX 上的 cmake 文件都按照 modern cmake 的做法做了修改,结果可见

Modern cmake 有什么好处就不说了,有很多文献可以查,而且我觉得按照目前官方文档的尿性,modern cmake无非是换一种方式踩坑,虽然坑的数量少了不少。

只说几个最核心的点。

首先 modern cmake 推荐按照 module 的方式拆分一个大工程,一个 module 对应一个 CMakeLists.txt,可以是一个 lib,也可以是一个 executable。

每个 module 抽象成一个 target,然后使用新的 target_* 属性去定义这个 target。并且每个 target 之间的属性是可以互相独立的。

工程最顶端是一个 CMakeLists.txt,定义一些全局的属性,然后通过 add_subdirectory() 来关联所有的 module。

几个自己研究过程中看过的一些资料:

Effective Modern CMake

Using Modern CMake Patterns to Enforce a Good Modular Design - Mathieu Ropert - CppCon 2017

CMake - Introduction and best practices

Effective CMake

最后,虽然 CMake 看起来已经要成为 C++ 的 de facto build system,但是靠谱的资料却没多少,也缺少像 C++ Core Guideline 这种有影响力的半官方指南。

Build Your Own HTTP Proxy Server Using Go

Go is a quite awesome programming language for building network applications. So I built my own HTTP proxy server using go last week.

To grasp the essence of how HTTP proxy server works, I choosed to implement it on TCP transport layer, forwarding TCP traffic directly.

Essentially, it runs a server, accepting incoming TCP connections and from which the server extracts target host of a request by parsing HTTP protocol messages. The server then establishes a connection to the target host, and finally operates as an intermedia, forwarding traffic from one host to another.

Implementing a TCP server which is able to handle concurrent requests uing go is easier than you thought: just runs a loop to accept requests, launching a new goroutine for each new connection:

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
type Server struct {
addr string
listener net.Listener
}

func (srv *Server) Start() {
var err error
srv.listener, err = net.Listen("tcp", srv.addr)
if err != nil {
log.Fatalf("Failed to listen at %s : %v", srv.addr, err)
}

log.Printf("Proxy is listening at %s", srv.addr)

srv.runLoop()
}

func (srv *Server) runLoop() {
for {
conn, err := srv.listener.Accept()
if err != nil {
log.Printf("Failed to accept an incoming connection : %v", err)
continue
}

go srv.handleConnection(conn)
}
}

func (srv *Server) handleConnection(conn net.Conn) {
c := newConnection(conn)
c.serve()
}

Monthly Read Posts in May 2018

Misc

怎样花两年时间去面试一个人

当前行业招聘的不靠谱,招揽优秀人员的难度大。

脱颖而出的核心:良好的阅读习惯 + Github 项目

这里说的两年是针对应届生来说的,对于已经工作的人来说,可以当作是虚指。

不过文中提到的,拥抱变化的三个核心点:

  1. 触动内心的大象
  2. 建立清晰明确的目标
  3. 扫清前进道路的障碍

颇有道理。


何判断一个技术(中间件/库/工具)的靠谱程度?

如何做技术选型

System & Architecture

聊聊Linux IO

A brief introduction to Linux I/O stack.

这篇 post 的质量在国内技术博客里算是少有的干货。

另,关于 page cache 和 buffer cache 的最新的内容,可以参考 Robert Love 在 quora 上的一个回答


CppCon 2015: John Farrier “Demystifying Floating Point”

工程实践上使用浮点数(IEEE-754)需要注意的一些坑。

看之前最好翻一下 CSAPP 中关于浮点数 IEEE-754 模型的基础知识

Build Your Own Threadpool With C++

Why Threadpool Matters

Why on the earth do we need thread-pool? The answer is obvious: for doing jobs behind the scenes.

That is, saying, you have a constant stream of incoming tasks to complete, and most of which either incur heavy computation or invovle device I/O, you definitely don’t want to execute them on your main thread, because it will block your main thread until the job is done, making your application less responsive.

However, with thread-pool, you can simply submit a task to the pool, then continue what was doing; the task will eventually be completed on a thread of the thread-pool.

If your processor has multiple cores, the task is possibly performed concurrently with your jobs on the main thread.

What Should a Threadpool Provide

Before we switch our focus to editor, we are better to think twice about what we can do with the thread-pool we will build.

浅析 RefCounted 和 WeakPtr:Chromium Base 篇

序言请移步此处

MSVC STL 的分析版本请移步此处

Libstdc++ 的分析版本请移步此处

Boost 的分析版本请移步此处

注 1:因为这不是第一篇分析,所以会直入主题,跳过文学写作常用的累赘的过渡。

注 2:这是系列最后一篇。

目标版本选择

Chromium tag 68.0.3421.1

代码位置:base/memory/ref_counted.{h, cc}

RefCountedBase 和 RefCounted

两个类实现了非线程安全的引用计数,即:内部计数使用的是 built-in integer

先看看 RefCountedBase 的大致结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class RefCountedBase {
protected:
explicit RefCountedBase(StartRefCountFromZeroTag);

explicit RefCountedBase(StartRefCountFromOneTag);

~RefCountedBase();

void AddRef() const;

bool Release() const;

private:
mutable uint32_t ref_count_ = 0;

#if DCHECK_IS_ON()
mutable bool needs_adopt_ref_ = false;
mutable bool in_dtor_ = false;
mutable SequenceChecker sequence_checker_;
#endif

DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
};

可以看出核心 ref_count_ 类型是 uint32_t

ctor 和 dtor 都被定义为 protected,说明这类使用做基类;同时提供了 AddRef()Release(),进行内部的计数增减。