Concurrent Connection 承載的上限

上個週末在噗浪上參與了關於一台 server 一個 IP 能夠承載多少 inbound connection 的討論. 才發現原來有不少朋友誤以為上限值是 65536 (2^16) 個, 或是雖然覺得這個說法哪裡怪怪的卻又說不出個道理來.

這篇文字的目的是希望可以在網路上留下中文的腳印, 幫助減少這樣的誤解.
Continue reading

On C-Style Cast in C++

Casts in C++

與 C 不同, C++ 提供了五種轉型的方式:

  1. dynamic_cast
  2. static_cast
  3. reinterpret_cast
  4. const_cast
  5. C-style (in syntax) cast

即便這是個每本 C++ 聖經都會說明的題材, 也一定會提醒避免 C-style (in syntax) cast. 實務上, 依然時常看到已有多年經驗的 programmer 會選擇使用 C-style (in syntax) cast. 先破梗一下, 前面一直強調 in syntax 的原因是, 雖然語法相同, C-style cast 在 C++ 中的語意不完全與 C 相同, 前者是後者的 super set. 這篇文字主要試圖說明 C-style (in syntax) cast 在 C++ 中到底是什麼, 以及為什麼避免.
Continue reading

In Code Documentation

在 G+ 河道上看到朋友貼了 cldoc 的連結, 也在 G+ 寫下自己對這類從 source code 以及其中的 annotation 產生文件之工具的看法. 本篇文字基本上為該 post 的中文版.

許多年以前, 我曾經大量使用從 source code 導出使用說明文件的工具, 特別是 Doxygen. 正如其首頁所說的 – “Doxygen is the de facto standard tool for generating documentation from annotated C++ sources”.

一段時間後我放棄了繼續使用這些工具. 我發現這類看似讓作者方便邊寫 code 就順便寫寫文件的工具, 實務上並沒有這麼美好.

就我有限經驗裡的觀察, 寫 code 與寫文件的不見得是同一 (批) 人. 由於做這兩種工作需要腦袋處於不同思考模式以及這兩種工作的產出多為軟體開發流程中不同階段所需, 即便有時作者是同一 (批) 人, 也不會在同一段時間一起進行.

有幾年工作經驗的 programmer 常會有這樣的認知; 只要不傷及可讀性與正確性, 手滑時在 code 或 comment 裏面留下的拼字/文法錯誤是無傷大雅的. 這類無礙的錯誤不見得會被修正, 特別是在 release 之後. 而給使用者看的說明文件可視為產品門面之一, 不太可能也照我們 programmer 的習慣得過且過 (誤). 因此, 我認為邊寫 code 邊寫 (給使用者看的) 文件不是一件 practical 的事情.

最糟糕的是把這類工具被用在 library. 當你為了修正拼字錯誤而的動到用來產生文件的 annotation, 它就是一個 revision. 理論上該出新 build 版號也要往下跳. 可是你要選擇把跳版號出新 build 這件事吃掉? 還是選擇對使用者解釋為何你把文件中的 teh 改成 the, 他們就要重新 compile…

IMHO, 使用 wiki 等專注於內容產生與協同作業 (而非排版美編) 的工具來編寫文件, 比用 editor 與 IDE 更有效也輕鬆多了.

Namespace std and Genericity

isocpp 看到一則 stackoverflow 上討論 std::initializer_list 的問題, 讓我想起曾打算提筆但一直沒動手的主題.

Swap and ADL

STL 定義的 user-defined type 大都提供了 std::swap(), 一個許多 algorithm 都需要的小 helper. 以 class template std::vector 來說, 長得像這樣:

namespace std
{
  template <typename T, typename Alloc = allocator<T> >
  class vector
  {
  public:
    void swap(vector& other);
    // ...
  };

  template </typename><typename T, typename Alloc>
  void swap(vector<t , Alloc>& lhs, vector</t><t , Alloc>& rhs)
  {
    lhs.swap(rhs); // Based on vector's swap member
  }
} // namespace std

C++ 把整個 standard library 都放在 namespace std, 這最大的好處是降低了 naming collision 發生的可能.

namespace LibX
{
  struct vector { ... };
  void swap(vector&, vector&);
}

#include <vector>

LibX::vector v1, v2;
LibX::swap(v1, v2);

using namespace LibX;
swap(v1, v2); // calls Libx::swap()

同時, 為了避免煩瑣的 fully qualified name (如 line 10) 以及 using directive (如 line 12), C++ 的 Argument Dependent Lookup 讓 compiler 利用我們傳給 function 的參數 幫你挑出對應的 candidate set. 因此, 即便把 line 12 的 using directive 拿掉, 上例依然是無誤的 code. 事實上, 甚至把 line 12 換成 using namespace std; ADL 還是會找到正確的 swap() overload, i.e. LibX::swap(). 只要你 follow Namespaces and the Interface Principle.

So far so good. Continue reading

Global Variables are Safer in C++11

正確的動態起始 global-variable/singleton 是一件苦差事. 直到 C++11 把 thread 及其配套納入標準. 以下是 n3337 (C++1y 第一個版本, 也就是說跟 C++11 官方標準文件之間只有微小差異) 是這麼說的:

An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization

用白話來說就是動態起始的 function static object 在第一次參考到時會被安全的起始, 並且會 block 其他在起始過程中也參考該 object 的 thread. 我的理解是這與使用 pthread_once 保護 function static object 的起始有相同的效果以及語意. 這下子程式簡單多了.

Re: Your Java programs won’t scale: A clear and concise explanation as to why

Just finished reading this two-part article +Nicholas Nezis shared and I am not buying.

If you haven’t read it, it would only take you a few minutes. If you are feeling lazy, it basically made the argument why Java doesn’t scale well by saying threading and locking is how Java scales with multi-processors, and:

“The more processors your throw at a Java program, the more often these data collisions happen, and you eventually hit a point where the whole JVM is simply bogged down in the process of managing and manipulating locks.”

Continue reading