目次: 射的
スピードシューティングを始めてから半年ほど経過しました。いよいよ11月末は公式大会(リミティッド - 一般社団法人日本トイガン射撃協会JTSA)です。今までの練習会のタイムをまとめておこうかと思います。
基本的に練習は週1回のみです。たまに練習以外のシューティング系イベントにも行きますが、さほどタイム上達とは関係ないはず。たぶん。
トータルタイムが2種類ある理由は、途中でStage 5の追加が正式発表されたためです。そのため7月まではStage 1〜4の合計(赤い線、右軸)、8月からはStage 1〜5の合計(青い線、右軸)が記録となります。ですが8月以降もStage 1〜4の合計タイムを見たら、今までと比べて上達or停滞が分かりやすいかも?と思い、表示しています。
最初こそ順調に早くなっていますが、ここ2〜3か月は伸びが止まっています、記録は正直だな〜。タイムは80秒台前半、脱・初心者レベル(※)くらいです。もうオジサンだし、あんまり根詰めたり無理するとケガするだけなんで、気楽&気長にやります。
(※)大会の前の公式記録会だと、総合(Hands Up)で84/101位、カテゴリ内(LM)で21/28位でした。
この記事にコメントする
目次: C言語とlibc
会社でpopenで作った子プロセスが残ってしまうが何とかならないか?という相談を受けて、面白そうだったので取り組んでみました。日記でも残しておきます。コード的には特に機密情報はありません。
マニュアルを読みましょう(Manpage of popen)。少しだけ解説するなら、子プロセスの入出力をパイプ経由で送ったり受け取ったりできるライブラリ関数です。
例えばyesコマンドをpopenで実行すると、出力パイプからはy y y y ... という文字列が読みだせます。
非常に便利なpopenですが、子プロセスが終了するかどうかは子プロセス次第、言い換えれば子プロセスを強制的に終了させる方法がないことが欠点です。
例えば、先ほど挙げたyesコマンドは勝手に終了しないコマンドの代表例です。popen関数を呼んだ親プロセスが終了しても、子プロセスのyesコマンドは終了しないまま残ります。
実はpopen関数は既存のライブラリ関数やシステムコールの組み合わせで実現できます。先にコードを載せましょうか。
/* SPDX-License-Identifier: Apache-2.0 */
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void usage(int argc, char *argv[])
{
printf("usage:\n"
" %s cmdline\n", argv[0]);
}
int main(int argc, char *argv[])
{
const char *cmdline;
pid_t pid, pgrp;
int pipefd[2];
FILE *fp;
int r;
if (argc <= 1) {
usage(argc, argv);
return -1;
}
cmdline = argv[1];
printf("cmdline: %s\n", cmdline);
// パイプを作成します。パイプに読み書きするファイルディスクリプタ(pipefd)2つが返されます。
// pipefd[0] が読み出し用、pipefd[1] が書き込み用です。
r = pipe2(pipefd, 0);
if (r == -1) {
perror("pipe2");
return -1;
}
// ファイルディスクリプタをFILE * でラップします。
// popenはFILE * を返すインタフェースなので、それに合わせるためです。
fp = fdopen(pipefd[0], "r");
if (fp == NULL) {
perror("fdopen");
return -1;
}
// 子プロセスを生成します。
// pidには子プロセスの場合は0、親プロセスの場合は子プロセスのプロセスIDが返されます。
pid = fork();
if (pid == -1) {
perror("fork");
return -1;
} else if (pid == 0) {
// child
// 子プロセスを新たなプロセスグループに移します。
// 理由はあとでkillを呼ぶときに親プロセスまで巻き添えにしないようにするためです。
// setpgidを呼ばない場合
// プロセスグループA: 親、子、指定したコマンド
// kill(プロセスグループA): 親も子もコマンドも全て強制終了してしまう
// setpgidを呼んだ場合
// プロセスグループA: 親
// プロセスグループB: 子、指定したコマンド
// kill(プロセスグループB): 子とコマンドのみ強制終了
r = setpgid(0, getpid());
if (r == -1) {
perror("setpgrp");
return -1;
}
// 子プロセスの標準出力を閉じ、パイプの書き込み用ファイルディスクリプタを代わりに使います。
// つまり子プロセスの出力がパイプに書き込まれます。
r = dup2(pipefd[1], 1);
if (r == -1) {
perror("dup(child)");
return -1;
}
// シェルを利用して引数に指定されたコマンドを実行します。
// シェルを利用する理由はpopenと同じ仕様(コマンド引数を1つの文字列で渡す)にしたいからです。
// シェルを挟まない場合は、複数の文字列に分割して渡す必要があります。
r = execl("/bin/sh", "sh", "-c", cmdline, (char *)NULL);
if (r == -1) {
perror("execl(child)");
return -1;
}
// not reach here
return -1;
}
// parent
// パイプから読みだすと子プロセスが標準出力に出そうとした文字列が読める
char buf[10];
memset(buf, 0, sizeof(buf));
fread(buf, 1, sizeof(buf) - 1, fp);
printf("read from pipe: %s\n", buf);
printf("sleep 5\n");
sleep(5);
// 子プロセスのプロセスグループを取得します。
// pidには子プロセスのプロセスIDが返されます。
// forkの部分も参照してください。
printf("getpgid() pid:%d\n", (int)pid);
pgrp = getpgid(pid);
if (pgrp == -1) {
perror("getpgid");
return -1;
}
// 子プロセスのプロセスグループを強制終了します。
printf("kill(SIGTERM) pgrp:%d\n", (int)pgrp);
r = kill(-pgrp, SIGTERM);
if (r == -1) {
perror("killpg");
return -1;
}
// 子プロセスが終了するまで待ちます。
printf("wait child pid:%d\n", (int)pid);
int wstat;
r = waitpid(-pid, &wstat, 0);
if (r == -1) {
perror("waitpid");
return -1;
}
if (r != pid) {
fprintf(stderr, "kill %d but terminated pid %d, why?\n", (int)pid, (int)r);
}
printf("done!!\n");
return 0;
}
そこそこ長いですね。
コードを見ると目がチカチカする方向けにコメントだけ抜き出しました。動きが分かりやすいと思います。
子プロセスはこんな動きです。
親プロセスはこんな動きです。
プロセスの親子関係はこうなります。
|-a.out,536208 yes | `-sh,536209 -c yes | `-yes,536210
もしコマンドがさらに孫、ひ孫プロセスを生成しても、プロセスグループが一緒である限りkillが効くはずです。
今回紹介した実装はpopenの完全な上位互換ではありません。理由としては入力側を扱えないこと、popenのようなAPIとして使えないこと、が挙げられますが、拡張は容易だと思います。
この記事にコメントする
今までお世話になった(なっている)ヘッドフォンたちをまとめておきます。
密閉タイプ。
オープンタイプ。
この記事にコメントする
IT系の職業に就いている人であれば、恐らく一度は目にしたことがあるInterfaceという雑誌があります。今回12月号に記事を寄稿しました。記事の見本は 2022年12月号 - Interface - CQ出版から見ることができます。
会社と出版社にご縁があったそうで、春頃から不定期連載が始まりました。特に会社の製品の宣伝はせず、RISC-V CPU開発に関してハードウェアからソフトウェアまで広く易しく扱う内容となっています。連載は全10回の予定、執筆者は会社の技術者で分担しており1人1記事ずつ担当しています。たぶん。
連載はちょうど真ん中で5回目となります。記事の内容はRISC-Vのツールチェーンの入門編で4ページほどの短い記事です。記事の内容はここでは公開できない(しばらく時間が経ったらOKらしいです)ので、もし気になるようでしたら雑誌をご覧くださいませ。
この記事にコメントする
| < | 2022 | > | ||||
| << | < | 11 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
| - | - | 1 | 2 | 3 | 4 | 5 |
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 | - | - | - |
wiki
Linux JM
Java API
2002年
2003年
2004年
2005年
2006年
2007年
2008年
2009年
2010年
2011年
2012年
2013年
2014年
2015年
2016年
2017年
2018年
2019年
2020年
2021年
2022年
2023年
2024年
2025年
過去日記について
アクセス統計
サーバ一覧
サイトの情報合計:
本日: