分类:'编程随笔' 的所有文章

关于Singleton (单件),线程安全

很就没写技术相关的blog了,Twitter和Buzz都很少用了,甚至很少有时间静下来思考、敲打键盘

今天面试问到static关键字的时候,有个应试者提到了Singleton的实现,就顺便多问了一点儿,回来自己又查了查

Singleton,单件,四人帮(GoF)写design pattern那本书的时候提出来的,一个进程内有且只有一个实例

说起这些Design Pattern,当时一看,我操,酷毙了,你不知道都不好意思跟别人说你是搞编程的

后来,渐渐的发现,没有银弹,只是有些Design Pattern或许有些淫荡,比如这个Singleton

一个最初的C++标准实现是这样的(S-V1):

//——————Implementation #1 ———————-
//s.h
class Singleton {
  private:
    Singleton();
    static Singleton* instance_;
  public:
    static Singleton* getInstance() {
        if (!instance_)
            instance_ = new Singleton();
        return instance_; } };

//s.cpp
Singleton* Singleton::pInstance_ = 0;

注意其中构造函数是私有的,所有只能通过getInstance构造,构造前又会先检查,所以只有一个

后来有人说,这样不是线程安全的,哦,那就简单点儿,这样吧(S-V2):

//——————Implementation #2 ———————-
//s.h
class Singleton {
  private:
    Singleton();
  public:
    static Singleton* getInstance() {
        static Singleton* instance_ = new Singleton();
        return instance_; } };

结果有人说,这个是依赖于编译器的,GCC能保证static的初始化不会出问题,但是VC就难说了。
于是,有人觉得既然第一个实现稍微改改就行了,只要加一个淫荡的锁(S-V1.1):

//——————Implementation #1.1 ———————-
//s.h
class Singleton {
  private:
    Singleton();
    static Singleton* instance_;
  public:
    static Singleton* getInstance() {
        lock_mutex();
        if (!instance_)
            instance_ = new Singleton();
        unlock_mutex();
        return instance_; } };

//s.cpp
Singleton* Singleton::pInstance_ = 0;

再后来,有人说这样也不行啊,每次get都加锁,效率太低了吧,那就更加淫荡一点,加锁之前我先check,加锁以后,我再check(S-V1.2):

//——————Implementation #1.2 ———————-
//s.h
class Singleton {
  private:
    Singleton();
    static Singleton* instance_;
  public:
    static Singleton* getInstance() {
        if (!instance_) {
          lock_mutex();
          if (!instance_)
              instance_ = new Singleton();
          unlock_mutex();}
        return instance_; } };

//s.cpp
Singleton* Singleton::pInstance_ = 0;

到这里,在搜索网络以前,我曾经认为已经OK了,但是多CPU多线程的复杂超乎想象,有人说,后一个实现不是线程安全的,因为对于instance的读和写并不是原子操作会发生写一半读一半的情况!
好吧,对效率没啥要求每个singleton就只会用个几次的用S-V1.1,没有多线程的用S-V2


========== 以下我也不是很懂的分割线 ==========

难道真的没办法优化S-V1.1了吗?

有办法,那个instance读一半写一半的情况对于int这个类型是不会发生的,那么,就多来一步,check一个int类型的标识吧:

//——————Implementation #1.3 ———————-
//s.h
class Singleton {
  private:
    Singleton();
    static Singleton* instance_;
    static int flag_;
  public:
    static Singleton* getInstance() {
        if (!flag_) {
          lock_mutex();
          if (!instance_)
              instance_ = new Singleton();
          unlock_mutex();}
          flag_ = 1;
        return instance_; } };

嘿嘿,这下你该满足了吧,NO!,还是有问题的,具体啥问题,参见这里那里,代码已经贴太多了。


进行到这里,你应该已经体会到,Singleton是很变态的,Design Pattern是很淫荡的。。。

Singleton最淫荡的地方在于:真正需要它的机会太少太少了,更多讨论参见:
[1] Singleton,你坏。。。在哪里?
[2] Singleton,银弹还是狗屎
[3] Singleton,何日才能用到你


路人甲:OMG,这是什么代码格式啊!
好吧,肯定有人不喜欢这个缩进,但是我敢肯定,肯定有人知道我喜欢Python了 :D

  • Share/Bookmark

最近写的几个Python脚本

最近太忙,忙的过程中写了七八个小脚本,其中一些比较通用的,贴在了代码发芽网上:

模拟《骇客帝国》中的滚屏效果,只需要几行简单的Python语句哦,以下是效果图:

matrix

Python语言: 简单的几句Python语句,模拟《骇客帝国》中的滚屏
#coding:utf-8

#
#简单的几句Python语句,模拟滚动的Matrix屏保
#
# 1. 打开Windows命令行(运行-》输入“cmd”然后回车)
# 2. 打开命令行属性设置,设置背景为黑色,前景为绿色
# 3. 执行这个脚本,就可以看到类似电影《骇客帝国》中的经典滚屏了 - 不过是反着的。。。
#
#呵呵,无聊之作。。。Alt+Enter全屏观看效果更好

import random, string
a = " " * 100 + string.printable
while True:
    print a[random.randint(0,len(a)-1)],


Python语言: 命令行小工具:输出系统Path中的符合条件的文件全路径,Python脚本
#What  : a small tool to locate files in system "PATH" variable

import sys

if len(sys.argv) < 2:
   print "  Usage:"
   print "    where.py test     #  normal  search"
   print "    where.py te*      #  blurred search"
   print "    where.py -x te*.cmd   #  regular expression search"
   sys.exit()
elif len(sys.argv) == 2:
   pattern = sys.argv[1].replace(".", "\\.").replace("*", "\\*").replace("?", ".?").lower()
else:
   pattern = sys.argv[2]#tricky, no "-x" checking here

import os
paths = [p for p in os.getenv('PATH').split(";") if p]
exts = [ext.lower() for ext in os.getenv('PATHEXT').split(";") if ext]
paths.append(".\\")
import re
for p in paths:
  if not os.path.isdir(p):
    continue
  for f in os.listdir(p):
    if re.search(pattern, f.lower()):
      is_exe = False
      for ext in exts:
        if f.endswith(ext):
          is_exe = True
          break
      if is_exe:
        print os.path.join(p,f)


Python语言: Python脚本获取Windows窗口标题,输出到命令行
#! /usr/bin/env python
# -*- coding: utf-8 -*-

from win32gui import *
titles = set()
def foo(hwnd,nouse):
  #去掉下面这句就所有都输出了,但是我不需要那么多
  if IsWindow(hwnd) and IsWindowEnabled(hwnd) and IsWindowVisible(hwnd):
    titles.add(GetWindowText(hwnd))

EnumWindows(foo, 0)
lt = [t for t in titles if t]
lt.sort()
for t in lt:
  print t

  • Share/Bookmark

关于25马问题的思考

题酷发芽网上的一个题目 “25匹赛马血拼Top5”:

有25匹马,共5个跑道,不用任何工具,请问

  1. 用几场比赛可分出前3名?
  2. 几场比赛可以分出前5名?
  3. 几场比赛可以给所有赛马排名?

Solrex Yang同学写了一篇文章比较全面的分析了这个问题,虽然后面有人指出其推理过程中的问题,但是可以看出主要的思想还是正确的,那就是尽量利用已经存在的信息。

今天无意间翻信翻到这个问题,突然想到,这其实是个可以编程求解的问题,而且跟我已经搞定的猜数字游戏求解过程很像

几点零星的想法,等到有时间再来细化:

1. 几次赛马以后,实际上生成了一个逻辑排序的图,每一次赛马,都要尽可能的把这个图变成一条**线**
2. 贪心的标准可以是:消除尽量多的分支
3. 每一步采用贪心算法,不一定能做到全盘最优 - 我求解猜数字游戏的时候就遇到过,贪心总是会有3、4个需要8步的,而全局最优却可以做到都在7步以内
4. 如果只是前三名,或许贪心算法得到的结果跟全局最优是一致的
5. 全局最优的算法,粗略一想,需要25!的计算量。要尽量减少计算的话,就要考虑做一些cache,滤掉重复性的计算,或许需要用到动态规划
6. 如果只是要求前三名,全盘最优应该很容易做到

先写这么多,等有时间再来写程序验证。。。

  • Share/Bookmark

贴代码 - 把文件夹压平

使用方法:在Windows下,保存该代码为flat.py,将其放到某个系统PATH所在目录下,并将.py加到系统PATHEXT变量中,然后打开命令行切换到某个目录下,输入flat,按指令行事。

注意改代码会自动删除当前目录下所有文件夹,请慎用

Python语言: 把文件夹压平 flatten folders
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# –filename:flat.py–
#
# 有时候需要把某个文件夹及其子文件夹下面的照片和视频通通导出到一个文件夹里
# 也就是把这个文件夹“压平”(flatten)
#
# 由于我的照片和视频文件名是不重复的,所以对于重复文件名的处理就没有做
#
#
print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
print "!!                                              !!"
print "!!     NOTICE! this will DESTROY your folder!   !!"
print "!!                                              !!"
print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"

secret = raw_input("Enter 123abc to continue:")
if secret != "123abc":
    print "you Entered " + secret, "WRONG answer!"
    print "Aborted!!!"
    import sys
    sys.exit()

import os
from os.path import join, getsize
for root, dirs, files in os.walk('.'):
    if root == ".": continue
    for file in files:
        cmd = 'move "' + join(root,file) + '" "' + file + '"'
        print cmd
        os.system(cmd)

for dir in os.listdir('.'):
    if not os.path.isdir(dir): continue
    cmd = "rd /s/q " + dir
    print cmd
    os.system(cmd)

  • Share/Bookmark

超级好用的日志(文本)查看和分析工具 - TextAnalysisTool.NET

TextAnalysisTool.NET

就要离开现在的公司了,收拾一下自己以前整理的资料,发现珍珠一枚:TextAnalysisTool.NET

这是我用过的最好的文本查看分析工具,特别是你经常查看某一种固定模式的文本/日志的时候,比如说测试程序结果,整体Build结果等等。

功能描述如下

  • 针对超大型文本设计和优化过,打开文件速度超快,却只消耗很少的内存
  • 可以对各种文本进行过滤并加色,这个功能在显示Pass和Fail结果的时候很好用,不同的结果可以标上不同的颜色
  • 过滤列表可以保存和加载,这个就更加方便了,如果有好多人经常查看同一个格式的文本,只要找个人做个过滤器配置文件,共享给大家就行了
  • 其他功能很简单,这里不说了,自己试试吧 :D 下载链接在此

    • Share/Bookmark

    下一页 »