这是一道机试题,大概的预期执行结果如下图所示
最近刚好在学习linux编程,便使用多线程及多进程分别实现了一遍,其中多线程较为简单,使用0/1信号量在线程间实现生产者/消费者即可;多进程则稍微复杂一些,信号量必须设置为进程间通信,且存放在共享内存中,才能被多个进程访问。
多线程的实现代码如下:
1 /*================================================================ 2 * Copyright (C) 2019 Ltd. All rights reserved. 3 * 4 * File Name :fork_test.c 5 * Author :Hamilton 6 * Date :2019-06-05 7 * Descriptor: 8 * 9 ================================================================*/ 10 11 12 #include <sys/types.h> 13 #include <sys/wait.h> 14 #include <unistd.h> 15 #include <unistd.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <semaphore.h> 19 #include <sys/mman.h> 20 #include <sys/stat.h> /* For mode constants */ 21 #include <fcntl.h> /* For O_* constants */ 22 #include <stdbool.h> 23 #include<pthread.h> 24 25 #define SHARED_MEM_NAME "/PRINTABC" 26 27 struct shared_memory { 28 sem_t sem[3]; 29 }; 30 31 const char ch[] = {'A', 'B', 'C'}; 32 int fd_shm = -1; 33 bool finish = false; 34 struct shared_memory *shared_mem_ptr = NULL; 35 36 void err_check(int ret) 37 { 38 if (ret < 0) 39 { 40 perror("error: %d. "); 41 exit(ret); 42 } 43 } 44 45 void err_exit(char *str) 46 { 47 perror(str); 48 exit(1); 49 } 50 51 void* thread_handler(void* arg) 52 { 53 int index = *(char*)arg - 'A'; 54 int pre = index ? (index - 1) : 2; 55 56 usleep(100000); 57 58 while (!finish) 59 { 60 sem_wait(&shared_mem_ptr->sem[pre]); 61 printf("%c ", ch[index]); 62 sem_post(&shared_mem_ptr->sem[index]); 63 usleep(100000); 64 } 65 pthread_exit(NULL); 66 } 67 68 void sig_handler(int signo) 69 { 70 if (signo == SIGINT) 71 { 72 printf("received SIGINT "); 73 finish = true; 74 } 75 } 76 77 int main() 78 { 79 int err, i = 0; 80 81 pthread_t tid[3]; 82 83 if (signal(SIGINT, sig_handler) == SIG_ERR) 84 printf(" can't catch SIGINT "); 85 86 // Get shared memory 87 if ((fd_shm = shm_open (SHARED_MEM_NAME, O_RDWR | O_CREAT, 0660)) < 0) 88 err_exit ("shm_open"); 89 90 if (ftruncate (fd_shm, sizeof (struct shared_memory)) == -1) 91 err_exit ("ftruncate"); 92 93 if ((shared_mem_ptr = mmap (NULL, sizeof (struct shared_memory), PROT_READ | PROT_WRITE, MAP_SHARED, 94 fd_shm, 0)) == MAP_FAILED) 95 err_exit ("mmap"); 96 97 err_check(sem_init(&shared_mem_ptr->sem[0], 0, 0)); 98 err_check(sem_init(&shared_mem_ptr->sem[1], 0, 0)); 99 err_check(sem_init(&shared_mem_ptr->sem[2], 0, 1)); 100 101 while(i < 3) 102 { 103 err = pthread_create(&(tid[i]), NULL, &thread_handler, (void*)&ch[i]); 104 if (err != 0) 105 printf(" can't create thread :[%s]", err); 106 else 107 printf(" Thread created successfully "); 108 i++; 109 } 110 111 for (i = 0; i < 3; i++) 112 { 113 pthread_join(tid[i], NULL); 114 sem_destroy(&shared_mem_ptr->sem[i]); 115 } 116 shm_unlink(SHARED_MEM_NAME); 117 printf("all threads have finished. "); 118 return 0; 119 }
多进程的实现代码如下:
1 /*================================================================ 2 * Copyright (C) 2019 Ltd. All rights reserved. 3 * 4 * File Name :fork_test.c 5 * Author :Hamilton 6 * Date :2019-06-05 7 * Descriptor: 8 * 9 ================================================================*/ 10 11 12 #include <sys/types.h> 13 #include <sys/wait.h> 14 #include <unistd.h> 15 #include <unistd.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <semaphore.h> 19 #include <sys/mman.h> 20 #include <sys/stat.h> /* For mode constants */ 21 #include <fcntl.h> /* For O_* constants */ 22 #include <stdbool.h> 23 24 #define SHARED_MEM_NAME "/PRINTABC" 25 26 struct shared_memory { 27 sem_t sem[3]; 28 }; 29 30 const char ch[] = {'A', 'B', 'C'}; 31 int fd_shm = -1; 32 bool finish = false; 33 struct shared_memory *shared_mem_ptr = NULL; 34 35 void err_check(int ret) 36 { 37 if (ret < 0) 38 { 39 perror("error: %d. "); 40 exit(ret); 41 } 42 } 43 44 void err_exit(char *str) 45 { 46 perror(str); 47 exit(1); 48 } 49 50 void process_handler(int index) 51 { 52 int pre = index ? (index - 1) : 2; 53 54 while (!finish) 55 { 56 sem_wait(&shared_mem_ptr->sem[pre]); 57 printf("%c ", ch[index]); 58 sem_post(&shared_mem_ptr->sem[index]); 59 usleep(100000); 60 } 61 } 62 63 void sig_handler(int signo) 64 { 65 if (signo == SIGINT) 66 { 67 printf("received SIGINT "); 68 finish = true; 69 } 70 } 71 72 int main() 73 { 74 pid_t pid; 75 76 if (signal(SIGINT, sig_handler) == SIG_ERR) 77 printf(" can't catch SIGINT "); 78 79 // Get shared memory 80 if ((fd_shm = shm_open (SHARED_MEM_NAME, O_RDWR | O_CREAT, 0660)) < 0) 81 err_exit ("shm_open"); 82 83 if (ftruncate (fd_shm, sizeof (struct shared_memory)) == -1) 84 err_exit ("ftruncate"); 85 86 if ((shared_mem_ptr = mmap (NULL, sizeof (struct shared_memory), PROT_READ | PROT_WRITE, MAP_SHARED, 87 fd_shm, 0)) == MAP_FAILED) 88 err_exit ("mmap"); 89 90 err_check(sem_init(&shared_mem_ptr->sem[0], 1, 0)); 91 err_check(sem_init(&shared_mem_ptr->sem[1], 1, 0)); 92 err_check(sem_init(&shared_mem_ptr->sem[2], 1, 1)); 93 94 pid = fork(); 95 96 if (pid < 0) 97 { 98 printf("Fork error. "); 99 exit(0); 100 } 101 else if (pid == 0) 102 { 103 printf("Process A, pid[%d]. ", (int)getpid()); 104 usleep(10000); 105 process_handler(0); 106 } 107 else 108 { 109 pid = fork(); 110 111 if (pid < 0) 112 { 113 printf("Fork error. "); 114 exit(0); 115 } 116 else if (pid == 0) 117 { 118 printf("Process B, pid[%d]. ", (int)getpid()); 119 process_handler(1); 120 } 121 else 122 { 123 printf("Process C, pid[%d]. ", (int)getpid()); 124 process_handler(2); 125 wait(NULL); 126 sem_destroy(&shared_mem_ptr->sem[0]); 127 sem_destroy(&shared_mem_ptr->sem[1]); 128 sem_destroy(&shared_mem_ptr->sem[2]); 129 shm_unlink(SHARED_MEM_NAME); 130 printf("all processes have finished. "); 131 } 132 } 133 return 0; 134 }
编译命令为:
gcc threadabc.c -o threadabc -lpthread -lrt
或者
gcc forkabc.c -o forkabc -lpthread -lrt
因使用到了多线程/进程,需连接 -lpthread;使用到了POSIX的信号量/共享内存相关,则需要连接 -lrt。关于linux多线程/多进程的开发及API接口的使用,可翻阅我近期摘抄的一些文章。
运行结果:
pi@raspberrypi:~/code/ipc/print_abc $ ./threadabc Thread created successfully Thread created successfully Thread created successfully A B C A B C A B C ^Creceived SIGINT all threads have finished. pi@raspberrypi:~/code/ipc/print_abc $ ./forkabc Process C, pid[7883]. Process A, pid[7884]. Process B, pid[7885]. A B C A B C A B C A B C ^Creceived SIGINT received SIGINT received SIGINT all processes have finished. pi@raspberrypi:~/code/ipc/print_abc $