Too many open filesにハマる
C/C++言語やって何十年になるんやねんっ!ってツッコミたくなるようなことで,何時間も悩んでしまいました.
プログラムがToo many open filesというエラーを出して死ぬので,iostreamやfopenの辺りをいくら調べてもバグが見つからず...
結局,悪かったのは次のようなルーチンでした.悪いところだけ抜き出した抜粋です.
#include<stdio.h> #include<stdlib.h> int main() { int i =0; while(1) { char s[]="XXXXXX"; printf("i=%d\n",i++); if(mkstemp(s)<0) { perror(NULL); exit(1); } printf("temp=%s\n",s); } return(0); }
要は,mkstemp()関数が,ユニークなテンポラリファイル名を作ってくれるだけで,ファイルディスクリプタを消費することを忘れていたのです.このプログラムを実行すると,私の環境では
# ./a.out i=0 temp=2fXVxE i=1 temp=AIH71k i=2 temp=Si0jw1 (中略) i=1019 temp=o6Fl9M i=1020 temp=GteWLB i=1021 Too many open files
となって死にます.
man mkstempをすれば書いてあるように,
説明
関 数 mkstemp() は引数 template から他と重ならないテンポラリファイル名を作成する。引数 template で指示する文字
列の後ろの 6 文字は XXXXXX である必要がある。この部分がファイル名を他と重ならないようにする文字で置き換えら れ
る 。 フ ァイルはアクセスモードがリード/ライト、そして許可モードが0666 (glibc 2.0.6 及びそれ以前の場合)、 0600
(glibc 2.0.7 及びそれ以降)で作成される。 template は書き換えられるため、文字列定数ではなく文字配列として宣言す
る ようにしなければならない。 mkstemp() が正常終了する時は、われわれが唯一のユーザーであることを保証するために
、テンポラリファイルは open(2) の O_EXCL 属性でオープンされる。返り値
成功すると、関数 mkstemp() はテンポラリファイルのファイルディスクリプタを返す。エラーの場合は、-1 を 返 し 、
errno を適切に設定する。
オープンされて,ファイルディスクリプタを返します.ちゃんと閉じなければならない.ああ,恥ずかしい.
例えば次のようにプログラムを修正すると,永久に動きます.
#include<stdio.h> #include<stdlib.h> #include<unistd.h> int main() { int i =0,j; while(1) { char s[]="XXXXXX"; printf("i=%d\n",i++); if((j=mkstemp(s))<0) { perror(NULL); exit(1); } printf("temp=%s\n",s); close(j); } return(0); }