diff --git a/.gitignore b/.gitignore index ce94c57..a881ae7 100644 --- a/.gitignore +++ b/.gitignore @@ -57,5 +57,6 @@ dkms.conf # User specific /kernel-sign +.vscode/ # End of https://www.toptal.com/developers/gitignore/api/c diff --git a/chp4_threads/cancel_threads_signal/.gitignore b/chp4_threads/cancel_threads_signal/.gitignore new file mode 100644 index 0000000..521eceb --- /dev/null +++ b/chp4_threads/cancel_threads_signal/.gitignore @@ -0,0 +1 @@ +cancel_threads \ No newline at end of file diff --git a/chp4_threads/cancel_threads_signal/Makefile b/chp4_threads/cancel_threads_signal/Makefile new file mode 100644 index 0000000..2b3c1cc --- /dev/null +++ b/chp4_threads/cancel_threads_signal/Makefile @@ -0,0 +1,18 @@ +CC=gcc +CFLAGS=-o cancel_threads -Wall -lpthread -lc -D_GNU_SOURCE +SRCS=main.c + +.DEFAULT_GOAL := build + +build: + $(CC) $(CFLAGS) -fsanitize=address -static-libasan $(SRCS) + +release: + $(CC) $(CFLAGS) $(SRCS) + +debug: + $(CC) $(CFLAGS) -fsanitize=address -static-libasan -ggdb $(SRCS) + gdb -q cancel_threads + +clean: + rm -f cancel_threads diff --git a/chp4_threads/cancel_threads_signal/main.c b/chp4_threads/cancel_threads_signal/main.c new file mode 100644 index 0000000..343192c --- /dev/null +++ b/chp4_threads/cancel_threads_signal/main.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +#define THREAD_COUNT 10 + +void *expensive_task(void *); +void send_finish_signal(void *); +void handler(int); + +pthread_t main_thread; +pthread_t threads[THREAD_COUNT]; + +int main(void) { + main_thread = pthread_self(); + + // Register handler for SIGCHLD signal + signal(SIGCHLD, handler); + + pthread_attr_t attr; + if (pthread_attr_init(&attr) != 0) { + perror("Error"); + return EXIT_FAILURE; + } + + int n[THREAD_COUNT]; + for (int i = 0; i < THREAD_COUNT; i++) { + n[i] = i; + printf("Create thread number %d\n", i); + pthread_create(&threads[i], &attr, expensive_task, (void *)&n[i]); + } + + for (int i = 0; i < THREAD_COUNT; i++) { + printf("Waiting thread number %d...\n", i); + pthread_join(threads[i], NULL); + printf("Thread %d joined\n", i); + } + + return EXIT_SUCCESS; +} + +void handler(int sig) { + printf("Caught signal %d\n", sig); + for (int i = 0; i < THREAD_COUNT; i++) { + pthread_cancel(threads[i]); + } +} + +void send_finish_signal(void *args) { + int *id = (int *)args; + printf("Thread %d send SIGCHLD signal\n", *id); + pthread_kill(main_thread, SIGCHLD); + printf("Thread %d cleanup handle is done\n", *id); +} + +void *expensive_task(void *args) { + pthread_cleanup_push(send_finish_signal, args); + const int tid = *((int *)args); + printf("Thread %d are running...\n", tid); + sleep(rand() % 31); + printf("Thread %d terminated!!!\n", tid); + pthread_cleanup_pop(1); + pthread_exit(0); +}