试题--创建三个进程/线程,依次输出 A、B、C

这是一道机试题,大概的预期执行结果如下图所示

最近刚好在学习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. \n");
 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 \n", 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\n");
 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("\ncan't catch SIGINT\n");
 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("\ncan't create thread :[%s]", err);
106         else
107             printf("\n Thread created successfully\n");
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.\n");
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. \n");
 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 \n", 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\n");
 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("\ncan't catch SIGINT\n");
 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.\n\n");
 99         exit(0);
100     }
101     else if (pid == 0)
102     {
103         printf("Process A, pid[%d]. \n", (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.\n\n");
114             exit(0);
115         }
116         else if (pid == 0)
117         {
118             printf("Process B, pid[%d]. \n", (int)getpid());
119             process_handler(1);
120         }
121         else
122         {
123             printf("Process C, pid[%d]. \n", (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.\n");
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 $

 

posted @ 2019-07-09 17:28  ba哥  阅读(1277)  评论(0编辑  收藏  举报