صفحه نخست

ارسال سیگنال با pthread_kill() به thread‌ها و دیدن نتایج

برنامه زیر ابتدا تمام سیگنال‌ها را بلاک می‌کند و بعد به تعدادی که در خط فرمان مشخص کرده‌ایم thread می‌سازد.

از طریق برنامه و با شیوه‌ای که در نمونه خروجی نشان داده شده است می‌توانیم سیگنال دلخواه را به thread دلخواه ارسال کنیم.

توجه کنید که SIGKILL و SIGSTOP قابل بلاک شدن نیستند و SIGCONT حتی در صورت بلاک بودن باز هم تحویل پروسس می‌شود (البته اگر این سیگنال بلاک شده باشد در لیست سیگنال‌های pending می‌ماند و سیگنال هندلر آن اجرا نمی‌شود تا زمانی که سیگنال را از حالت بلاک خارج کنیم).

سیگنال SIGUSR1 برای پیاده‌سازی برنامه مورد استفاده قرار گرفته است و به همین خاطر قابل ارسال به thread ها نیست.

برنامه باید با کتابخانه pthread لینک شود. طریقه کامپایل به صورت زیر است.

$ gcc file.c -lpthread
/**
 * Thread signal sending.
 *
 * Mohsen safari
 * mstafreshi.ir
 */

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

struct {
	int index;
	pthread_t tid;
} *thread;

void sigusr1Handler(int sig) { }

void
exitEN(int s, char *str)
{
	if (str != NULL)
		fprintf(stderr, "%s: ", str);
	fprintf(stderr, "%s\n", strerror(s));
	exit(s);
}

void *
threadFunc(void *arg)
{
	sigset_t mask;
	int i, j, count, id;
	
	id = *((int *) arg);

	for(;;) {
		sigemptyset(&mask);
		if (sigpending(&mask) == -1) {
			fprintf(stderr, "sigpending");
			pthread_exit(NULL);
		}

		for (j = 1; j < NSIG; j++) {
			if (sigismember(&mask, j)) {
				count = 1;
				printf("====== [thread %d] ======\n", id + 1);
				for (i = j ; i < NSIG; i++) {
					if (sigismember(&mask, i)) {
						printf("%d- %s (%d)\n", count, strsignal(i), i);
						count++;
					}
				}

				break;
			}
		}

		pause();
	}
}

int
main(int argc, char *argv[])
{
	int s, thrNum, sigNum, thrCount;
	char buf[BUFSIZ];
	struct sigaction sa;

	sigset_t mask;
	pthread_t recvThr;

	if (argc != 2) {
		fprintf(stderr, "usage: %s threads-count\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	
	thrCount = atoi(argv[1]);
	if (thrCount < 1)
		errx(EXIT_FAILURE, "threads-count must be at leaset 1");

	thread = calloc(thrCount, sizeof(*thread));
	if (thread == NULL)
		err(EXIT_FAILURE, "calloc");

	sigfillset(&mask);
	sigdelset(&mask, SIGQUIT);
	sigdelset(&mask, SIGUSR1);
	
	sigemptyset(&sa.sa_mask);
	sa.sa_handler = sigusr1Handler;
	if (sigaction(SIGUSR1, &sa, NULL) == -1)
		err(EXIT_FAILURE, "sigaction");

	if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
		err(EXIT_FAILURE, "procsigmask");

	for (int j = 0; j < thrCount; j++) {
		thread[j].index = j;
		s = pthread_create(&thread[j].tid, NULL, threadFunc, &thread[j].index);
		if (s != 0)
			exitEN(s, "pthread_create");
	}

	while (1) {
		if (fgets(buf, BUFSIZ, stdin) == NULL)
			break;

		if (buf[0] == '\n') {
			fprintf(stderr, "usage: sig thread-number sig-number\n");
			continue;
		}

		if (sscanf(buf, "sig %d %d", &thrNum, &sigNum) != 2) {
			warnx("invalid data");
			continue;
		}

		if (thrNum < 1 || thrNum > thrCount) {
			warnx("invalid thread-num: %d", thrNum);
			continue;
		}

		if (sigNum < 0 || sigNum >= NSIG) {
			warnx("invalid sig-num: %d", sigNum);
			continue;
		}

		if (sigNum == SIGUSR1) {
			warnx("SIGUSR1 is in use. Not allwed for user!");
			continue;
		}
			
		if (pthread_kill(thread[thrNum - 1].tid, sigNum) == -1)
			warn("pthread_kill");
		
		if (pthread_kill(thread[thrNum - 1].tid, SIGUSR1) == -1)
			warn("pthread_kill-SIGUSR1");
	}

	exit(EXIT_SUCCESS);
}

نمونه خروجی برنامه به صورت زیر است:

$ ./a.out 7
sig 7 1
====== [thread 7] ======
1- Hangup (1)
sig 7 2
====== [thread 7] ======
1- Hangup (1)
2- Interrupt (2)
sig 7 4
====== [thread 7] ======
1- Hangup (1)
2- Interrupt (2)
3- Illegal instruction (4)
sig 1 7
====== [thread 1] ======
1- Bus error (7)
sig 1 65
a.out: invalid sig-num: 65
sig 1 8
====== [thread 1] ======
1- Bus error (7)
2- Floating point exception (8)
sig 4 56
====== [thread 4] ======
1- Real-time signal 22 (56)
sig 4 52
====== [thread 4] ======
1- Real-time signal 18 (52)
2- Real-time signal 22 (56)

 

کلیه حقوق برای دارنده‌ی سایت محفوظ است.