2018年10月7日

记录世界记录你

7年前,最后一篇博客日志,宣告了这个博客暂告一个段落。今天,I'm back。;-)

我非常喜欢快手的 slogan,「记录世界记录你」。许多人说,多年后回头看曾经的自己都觉得很逗比;我当然也不例外,站在30+的年纪上,回想过去发生的种种,难免产生这种感觉。So many things happened, so many things changed. Time flows, never stops its pace.

最近喜欢上豆瓣刷高分电影,今晚刷的是《燃情岁月》。很多年前豆瓣还是个很小的社区时,阿北表示「看电影是在经历一种别样的人生,f**k 那些在电影院里喧哗的人」。我是个记忆力比理解力强、后知后觉的人,许多一时间无法理解的事情会被下意识地记住,在之后某个 aha moment 突然理解。可能刚才发生的就是这样的一个 aha moment。

同时间和解,同过去和解,同现在的自己和解,对未来的自己说「你好」。

Samuel 生活在他构造的世界中,善良淳朴;Tristan 和自然与野兽走的最近,洒脱;Alfred 学习和遵从社会规则,文明的「社会人」。People don't change,所谓的 spiritual kernel 很难改变,所以才有人说「成长需要反人性」。Alfred 最后的一枪是点睛之笔,化解了兄弟和父子之间的隔阂。

知道自己适合什么、想要什么,是多么困难的一件事情呀。Know yourself 这句古希腊箴言,真是人生智慧。BTW,查了下另外两句箴言,「妄立誓则祸近」和「凡事不过分」,同样是朴素简单到太容易被忘记。

这两天买了本书,《Designing data-intensive applications》,非常厚的一本书,随手一翻,涵盖的主题很广,不禁想起了 Don Knuth 高德纳老爷子说的「我的书中的一两页纸可能是一个人的一生」以及自传开头的玩笑话「Don Knuth 真的只是一个人吗」,也不免想起前两天刷的电影《青年马克思》,坚持独立思考、深入实践的年轻人,以及坚持构建理论体系大厦的中年人(查了下《资本论》出版时马克思已经49岁了,forever young 是一种精神)。What a admirable life.

充盈的人生该是什么样子?人生太短,不虚度时间,做好选择,持之以恒,一贯以穿之;人生很长,用适当的频率坚持,无论是力争向上还是虚妄念头,都坚持「凡事不过分」;立长志,坚持先谋后动,对短期诱惑说不。

Ok,流水账到此结束。记录世界记录你。

2011年1月23日

2010年8月2日

Tcl 多线程初步

其实对线程和并发这一块了解相当少,基本上不太清楚究竟什么情况下应该使用并发模型、什么情况下不该采取此类模型。昨天在豆瓣看到一本书,《JAVA并发编程实践》。评价挺高,准备在淘宝入手盗版版本(不是俺想要支持盗版猖獗,只是卓越当当都没货啊。好吧,这其实不是借口…… 囧)。

这里简单的对 Tcl 语言的线程做一下阐述。算是备忘。后续对并发这一块,如果有机会深入了解的话,再补充更新吧。

Tcl 的线程模型主要内容(基于 ActiveTcl 8.5 中包含的 Thread 2.6.5 版本),仅说一下自己觉得印象比较深刻的几点:
  1. 线程的创建、保存、释放等操作。
    thread::create ?-joinable? ?-preserved? ?tcl_script?
    其中开启的 -joinable 参数,可以保证其他的线程来「join」这个线程,从而使得只有当这个线程结束时,join 它的另外一个线程才能够结束。
    thread::wait
    只有通过这条命令创建的线程,才会被启用引用计数机制,才能够执行正常的 thread::preserve 和 thread::release 操作。所有此命令之后的命令,会在线程被释放之后执行(貌似有点类似于析构函数的角色)。
  2. 任何时候,Tcl 如果是以开启线程的方式编译的,那么载入 Thread 包之后,便存在一个主线程。要确保这个「主线程」是最后被中止的。即,这个主线程退出时,不能够存在其他活动的、没有被释放的线程。这一点可以通过上述的 -joinable 参数来保证。具体参见这里
  3. 线程间发送命令。
    thread::send ?-async? $tcl_script
    同步和异步的方式。前者阻塞(不再服务自身的 event loop),后者立即返回。
  4. 错误处理。
    分成若干情况:创建线程、异步发送命令时出错,不写全局错误代码和错误信息,仅仅将错误信息反馈在标准输出上;同步发送命令时出错,错误信息和错误代码将反射到 sender 线程中。置位某个线程的 -unwindonerror 参数后,一旦其执行某命令(其他线程发送给他的命令)出错,此线程即中止。
  5. 线程共享变量。
    每个线程其实都包含一个独立的 Tcl 解释器。然而通过 tsv::set array_name element_name "element_value" 命令创建的共享变量,却可以在各个线程间共享,且不需要考虑线程间写数据的锁机制,这个命令本身就是 atomic 的。在获取的时候之需要使用 tsv::get array_name element_name 就可以了。
  6. 互斥量。条件变量。
    # thread::mutex
    # thread::mutex create
    # thread::mutex destroy $mutex
    # thread::mutex lock $mutex
    # thread::mutex unlock $mutex
    # thread::cond
    # thread::cond create
    # thread::cond destroy $cond
    # thread::cond notify $cond
    # thread::cond wait $cond $mutex
    具体的使用可以参考《Practical Programming in Tcl and Tk》第21章,或者这个链接。前者讲解的挺细致的。
  7. 线程池。
    目前我对这个只有一点概念,勉强大致知道怎么回事。就不多说了。具体可以参考这个链接
    有一点印象深刻:当一个线程给某个线程池 post 命令之后,这条命令本身是 block 的,然而其本身依然是可以服务 event loop 的(并非彻底阻塞了)。
  8. 重复一下,相当于提醒自己。任何命令都需要注意区分,其是否存在阻塞和非阻塞的情况。 阻塞情况下,又要注意区分,此命令执行后,该线程是否还能够服务于自身的 event loop 等等。
最后贴一段代码,写的比较乱,不过基本体现了上述的很多方面(包括线程、线程间共享变量、线程池等等),也体现了当前我对线程这一块的不熟悉。 >_<执行结果如下:
Commands: thread_2 --> thread_1.
Commands: thread_1 --> tpool.
Blocked, still with event loop service.
Commands: thread_2 --> thread_1.
Commands: thread_2 --> thread_1.
Commands: thread_2 --> thread_1.
Commands: thread_2 --> thread_1.
Commands: thread_2 --> thread_1.
tpool job 1 finish.
Commands: thread_2 --> thread_1.
Commands: thread_2 --> thread_1.
Commands: thread_2 --> thread_1.
Commands: thread_2 --> thread_1.
main thread: finished.
thread_2: finished.
Creative Commons License 转载请指明出处. 谢谢合作.
/***********************
author: jtuki
http://jtuki.blogspot.com/
***********************/