博文

目前显示的是 2018的博文

COM与Windows Thread Pool API无法兼容?

在调用任何COM方法前,需要先调用CoInitializeEx。 在线程即将结束的时候,每个CoInitializeEx应当对应一个CoUninitialize。但是对于Windows ThreadPool来说,它的线程的创建和销毁不受用户控制,所以只有两种解决办法:

1. 在每个task的开始调用CoInitializeEx,task的结束调用CoUninitialize。
2. 手动创建一个线程池专用于运行COM任务。这两个线程池之间用类似于消息传递的方式通信。

这两种方法怎么看怎么傻。

刚把国土安全第七季看完了

一共12集,昨天看了6集,今天又看了6集。算是一口气看完了。心有点累。有点厌倦。

这个剧的特点是,从第一季到现在,它每一次都是找个近期热点的政治话题,然后杜撰一串阴谋,不巧被女主角发现了,一次次的拯救了这个国家。前几季的节奏还比较缓,有时间做些细节刻画、内心描写。后面这些就越来越随大流了,纯粹的商业剧情片,不太能打动我。

当一个国家陷入内部纷争的时候,他的行政官员们不去想怎么团结起来解决内部矛盾,而是种种阴谋论,把这一切都归罪为境外敌对势力煽动,我觉得这荒谬。一个国家的民主制度不可能靠几个间谍来拯救。社交媒体上确实是假新闻横行,但难道对策就是实施内容过滤新闻管制吗?我真的觉得很失望。举个例子,新浪微博经常会把某些热门微博内容标为“虚假”。它的原意是这样看到的人就知道这是假的,不会信。它觉得比直接删掉还要好。但是我每次看到这样的标记的时候觉得很刺眼。我觉得这是对我的侮辱。任何一个人,都必须有自主的辨明是非的能力。我相信阳光之下并无谎言。而不是搞什么“权威发布”、“官方打假”。回过头来,当我看到那个满嘴胡言的talk show主持人的时候,我反复在想,这种腔调是如此的耳熟,我在哪听过?

这剧出下一季我估计是不会看了。

回忆一部电影:花季雨季

花季雨季上映于1997年,它热映的时候我正在上初中,一片懵懂。就记住片子里说,16岁时花季,17岁是雨季。于是我就无比渴望我的16、17岁。同时也很好奇,18岁又是什么。

影片中有一个小小的情节,影响了我的一生。片子里有一个学生,很勤奋,成绩很好,但是并不遭班主任的喜欢。他在家里挂了一幅字:“吃得苦中苦,方为人上人”。班主任看到后表示很忧虑,很不赞同这样的想法。她说: "一个人的真正价值首先决定于他在什么程度上和什么意义上从自我中解放出来"。其实当时我并不是很懂她在说什么,但是经过我的老师的解释后我勉强明白,争做“人上人”的想法是错的。虽然我不是特别明白它为什么是错的。

于是,这么多年我一直在思考这个问题。时不时的就会回想起这个,不断的警惕自己,不要有争做“人上人”的想法。然后逐渐的我就发现我与我这代人的主流价值观渐行渐远。我无意于说谁对谁错。在美国至少我学会了"no judgement"。我坦然接受我的失败。我一再错过了买房的机会,创业成功的机会。别人花4年升到Senior Software Engineer而我却花了10年。我若更“上进”一些生活必定大有不同。但我不太后悔。我只是回过头来很感谢这部电影,在我青春期给我留下了不可抹去的思想塑造。当我回头看我这失败的10年的时候,我内心是平静的。不怕你嘲笑,做Windows开发一直是我的梦想,现在我实现了。若有来生,我也许不会选择当一名软件工程师。我希望我能完成博士学位,然后成为一名医生、社会工作者,或者哪怕是个政客。


Thinking on thread pool

大多数应用程序的线程池的实现都是纯用户态的。这其中有两个例外,微软的Windows new ThreadPool API和苹果的GCD.

Availability:

首次发布的系统时间Windows New Thread Pool APIVista2006年GCDOS X 10.62009年
(Windows还有一套老的ThreadPool API,是从XP开始提供的,那个是纯用户态的)

传统来说,线程池的实现非常简单,启动几个线程,然后配合一个线程安全的队列就可以了。大约只需要几百行代码,利用C++标准库现有的thead/mutex/condition_variable这些原语就很容易实现一个跨操作系统的线程池。

但是往往,我们会发现同一进程里会有多个线程池,它们分别是针对不同的业务逻辑需要。于是如何设置每个线程池的大小就成了一个经验性的问题。如果我们可以实现一个通用的线程池,使得进程可以把它所有不同的workload都混在这同一个线程池中执行,同时这个线程池可以自动调节活跃线程数量使其等于CPU物理核数,那么这就是最理想的。

如果线程池收到的每个任务,在执行的时候都不会有任何阻塞或者等待,也就是说每时每秒都在进行纯CPU计算。那么我们线程的创建/销毁的策略就非常简单:让线程数量静态的等于这台机器总的CPU核数。这样就是最优的。

但是实际上用户是有可能进行阻塞式的操作,如:
1.  锁竞争
2.  等待某个事件(如条件变量,Windows Event)
3.  阻塞式IO

理想情况下不应该有任何阻塞性操作。但是实际上你常常会调用一些第三方的库(如MySQL Client),而它们不支持异步IO或非阻塞式IO,把它代码彻底改写又不大可能。

另外,当所有的线程都处于blocking状态时,就会导致新来的task无法被处理。我们称之为饥饿(starvation)。最严重的情况下,整个线程池里所有的线程都陷入无限的等待中,类似于死锁。为了防止这样的事情发生,需要一些简单粗暴的编程规则,如:等待task完成的线程不能与执行该task的线程在同一个线程池里。

出于以下几种原因,我们会希望使用操作系统特殊的API,而不是C++标准库的那些thread/mutex/condition_variable来实现线程池。

1. 让活跃的线程数量可以根据IO负载来调节。如果一个线程陷入I…

LLVM 6.0.1发布,附下载地址及安装办法

官方文档: http://releases.llvm.org/6.0.0/docs/CMake.html

下载地址:
http://llvm.org/releases/6.0.0/

如果你没有找到与你系统对应的二进制包,可按下述步骤编译及安装:
下载源代码set -e mkdir llvm cd llvm LLVM_VERSION=6.0.1 aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/$LLVM_VERSION/llvm-$LLVM_VERSION.src.tar.xz aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/$LLVM_VERSION/cfe-$LLVM_VERSION.src.tar.xz aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/$LLVM_VERSION/compiler-rt-$LLVM_VERSION.src.tar.xz aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/$LLVM_VERSION/lldb-$LLVM_VERSION.src.tar.xz aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/$LLVM_VERSION/lld-$LLVM_VERSION.src.tar.xz aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/$LLVM_VERSION/clang-tools-extra-$LLVM_VERSION.src.tar.xz aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/$LLVM_VERSION/polly-$LLVM_VERSION.src.tar.xz aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/$LLVM_VERSION/openmp-$LLVM_VERSION.src.tar.xz for filename in *.xz; do tar -Jxf $filename ; done mv cfe-$LLVM_VERSI…

异步执行task的时候,一定要把完成通知放在最末尾的地方

请看下面这段示例代码。这段程序的目的是计算1*2+3*4+5*6=? 。它试图并行的计算3个乘法,然后汇总。如果乘号的两边是大矩阵或者向量,这样的多线程计算会得到很好的加速。
#include <atomic> #include <condition_variable> #include <mutex> #include <pthread.h> #include <stdio.h> #include <thread> #include <unistd.h> #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName &) = delete; \ void operator=(const TypeName &) = delete class SubTask; void *runSubTask(void *); class Job { public: Job() {} void compute(); void onSubTaskFinished() { if (--active_tasks == 0) { cv_.notify_all(); } } std::atomic<size_t> active_tasks; private: std::mutex m_; std::condition_variable cv_; DISALLOW_COPY_AND_ASSIGN(Job); }; class SubTask { public: int v1; int v2; std::atomic<int> *result; Job *parent; int task_id; ~SubTask() { printf("Sub task %d finished\n", task_id); } //BUG!…

Linux调整分区及备份恢复小结

如果想要扩展一个分区,那么只能向后扩展,不能向前扩展。
调整一个分区的大小分为三步:

1. 用fdisk/gdisk调整分区表。
     不能直接modify。需要先删除该分区,再新建。
2. fsck
3. 用resize2fs调整元数据信息

resize2fs要求分区的起始位置不能变。

"when  recreating the partition, make sure you create it with the same starting disk cylinder as before!  Otherwise, the resize operation will certainly not work, and you  may  lose  your  entire filesystem."

如果需要往前移动,那么最好是先备份再恢复。作为一个FreeBSD的老用户,我非常信赖dump/restore这两个命令。简略步骤如下:
$ mkfs.ext4 /dev/sda3
$ mount /dev/sda3 /mnt/a
$ cd /mnt/a
$ dump -a0f - /dev/sda4 | restore -rf -





linux wifi regulatory database在新版本kernel中的更改

更新linux kernel后经常会遇到这样的错误信息:

“Direct firmware load for regulatory.db failed”

这是因为新版本的kernel更改了load regulatory.db 的方式
解决办法是手动从https://mirrors.edge.kernel.org/pub/software/network/wireless-regdb/ 下载最新的包,解压缩后把regulatory.db regulatory.db.p7s 复制到/lib/firmware即可

然后reboot,看到这样的信息就对了
"cfg80211: Loading compiled-in X.509 certificates for regulatory database"


参考:https://wireless.wiki.kernel.org/en/developers/regulatory/wireless-regdb