見出し画像

C言語教室 第25回 - コールバック関数(回答提出)

こちらの課題回答です。

ずいぶん昔に「ctrl+c」をきかないようにしたことがあったような気がする。もしかしたら、前世紀のことかもしれない(笑)。無効にすることが目的だったのでハンドラは持たなかったかもしれない。

今回は、
signal」ではなく、
sigaction」を使ってみました。

sigaction() 関数は signal() インターフェースに代わるものであり、優先的に使用する必要があります。

とあったので。

改めてシグナル機能を見るといろんなハンドラがあるのね。

課題より少し手をのばして次のものも拾ってみた。

  • (1)Abort

  • (2)raise

  • (3)Alarm

「(1)Abort」はシグナルを拾っても、とにかく Abort しちゃうのね。マスクはできない。

「(2)raise」は意識的にシグナルを発生させる標準関数で、「SIGUSR1」のシグナルが発生します。

「(3)Alarm」は3秒経ったらシグナルが発生します。

ハンドラで「printf」文を使っていいのか、とも思うがテストプログラムなのでよしとします。

他にも気になるシグナルがいろいろあって試してみたかったりする。
「0除算」を拾えるなんて知らなかった。

コールバックの手法はいろいろと便利なんだけど、特にマルチタスク、マルチスレッドで動作しているときは、どのタスク、どのスレッドで動くことになるのかを忘れがちになったりするので注意が必要かと思われる。シグナルの「Abort」や「0除算」などもそうで、CPUの例外割り込みとの関係も考えると、「printf文のような入出力を使っていいの?」などと疑問が頭をよぎる。

では、回答コードです。

コード

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>

char* str_sig(int sig)
{
	char* str = "";
	switch (sig)
	{
		//case SIGABND:   str = "SIGABND";   break;
		case SIGABRT:   str = "SIGABRT";   break;
		case SIGALRM:   str = "SIGALRM";   break;
		case SIGBUS:    str = "SIGBUS";    break;
		case SIGFPE:    str = "SIGFPE";    break;
		case SIGHUP:    str = "SIGHUP";    break;
		case SIGILL:    str = "SIGILL";    break;
		case SIGINT:    str = "SIGINT";    break;
		case SIGKILL:   str = "SIGKILL";   break;
		case SIGPIPE:   str = "SIGPIPE";   break;
		case SIGPOLL:   str = "SIGPOLL";   break;
		case SIGPROF:   str = "SIGPROF";   break;
		case SIGQUIT:   str = "SIGQUIT";   break;
		case SIGSEGV:   str = "SIGSEGV";   break;
		case SIGSYS:    str = "SIGSYS";    break;
		case SIGTERM:   str = "SIGTERM";   break;
		case SIGTRAP:   str = "SIGTRAP";   break;
		case SIGURG:    str = "SIGURG";    break;
		case SIGUSR1:   str = "SIGUSR1";   break;
		case SIGUSR2:   str = "SIGUSR2";   break;
		case SIGVTALRM: str = "SIGVTALRM"; break;
		case SIGXCPU:   str = "SIGXCPU";   break;
		case SIGXFSZ:   str = "SIGXFSZ";   break;
		case SIGCHLD:   str = "SIGCHLD";   break;
		//case SIGIO:     str = "SIGIO";     break;
		//case SIGIOERR:  str = "SIGIOERR";  break;
		case SIGWINCH:  str = "SIGWINCH";  break;
		case SIGSTOP:   str = "SIGSTOP";   break;
		case SIGTSTP:   str = "SIGTSTP";   break;
		//case SIGTSTP:   str = "SIGTSTP";   break;
		case SIGTTIN:   str = "SIGTTIN";   break;
		case SIGTTOU:   str = "SIGTTOU";   break;
		case SIGCONT:   str = "SIGCONT";   break;
	}

	return str;
}

int ctrlc_cnt = 0;
void sigint(int sig, siginfo_t * siginfo, void * tmp)
{
	ctrlc_cnt++;
	printf("\n");
	printf("sigint : sig=%d[%s] ctrlc_cnt=%d \n", 
			sig, str_sig(sig), ctrlc_cnt);

	if (2 <= ctrlc_cnt)
	{
		exit(0);
	}
}

void sigabrt(int sig, siginfo_t * siginfo, void * tmp)
{
	printf("sigabrt : sig=%d[%s]\n", sig, str_sig(sig));
}

void sigusr1(int sig, siginfo_t * siginfo, void * tmp)
{
	printf("sigusr1 : sig=%d[%s]\n", sig, str_sig(sig));
}

bool alarmed = false;
void sigalrm(int sig, siginfo_t * siginfo, void * tmp)
{
	alarmed = true;
	printf("\n");
	printf("sigalrm : sig=%d[%s]\n", sig, str_sig(sig));
}

int main()
{
	struct sigaction sact = {0};
	sigemptyset(&sact.sa_mask);
	sact.sa_flags = 0;
	sact.sa_handler = SIG_IGN;

	sact.sa_sigaction = sigint;
	sigaction(SIGINT, &sact, NULL);

	sact.sa_sigaction = sigabrt;
	sigaction(SIGABRT, &sact, NULL);

	sact.sa_sigaction = sigusr1;
	sigaction(SIGUSR1, &sact, NULL);

	sact.sa_sigaction = sigalrm;
	sigaction(SIGALRM, &sact, NULL);

	while (1)
	{
		printf("=======================\n");
		printf("0.endless loop\n");
		printf("1.abort\n");
		printf("2.raise(SIGUSR1)\n");
		printf("3.alarm(3)\n");
		printf("=======================\n");
		printf("select number -> ");

		int num = 0;
		int n = scanf("%d", &num);
		if (n != 1)
		{
			continue;
		}

		if (num == 0)
		{
			ctrlc_cnt = 0;
			while (1) {}
		}

		else if (num == 1)
		{
			abort();
		}

		else if (num == 2)
		{
			raise(SIGUSR1);
		}

		else if (num == 3)
		{
			alarm(3);
			alarmed = false;
			while (1)
			{
				if (alarmed == true)
				{
					break;
				}
			}
		}

		else
		{
			break;
		}
	}

	return 0;
}

実行結果

~/c/c25 $ sig_1
=======================
0.endless loop
1.abort
2.raise(SIGUSR1)
3.alarm(3)
=======================
select number -> 0
^C
sigint : sig=2[SIGINT] ctrlc_cnt=1
^C
sigint : sig=2[SIGINT] ctrlc_cnt=2
~/c/c25 $ sig_1
=======================
0.endless loop
1.abort
2.raise(SIGUSR1)
3.alarm(3)
=======================
select number -> 1
sigabrt : sig=6[SIGABRT]
Aborted
~/c/c25 $ sig_1
=======================
0.endless loop
1.abort
2.raise(SIGUSR1)
3.alarm(3)
=======================
select number -> 2
sigusr1 : sig=10[SIGUSR1]
=======================
0.endless loop
1.abort
2.raise(SIGUSR1)
3.alarm(3)
=======================
select number -> 3

sigalrm : sig=14[SIGALRM]
=======================
0.endless loop
1.abort
2.raise(SIGUSR1)
3.alarm(3)
=======================
select number -> 9
~/c/c25 $

この記事が気に入ったらサポートをしてみませんか?