发帖
11 0 0

unix环境高级编程学习——进程管理

CHENQIGUANG1998
金牌会员

20

主题

84

回帖

2384

积分

金牌会员

积分
2384
技术杂谈 1802 11 2023-9-14 16:47:54
1. 进程概述
在UNIX和类UNIX系统中,进程是执行程序的基本单位。每个进程都有一个独立的地址空间,有自己的程序代码、数据和系统资源。进程可以创建其他进程(子进程),也可以与其他进程(父进程)终止关联。
2. 进程控制
在UNIX环境下,有多种方式可以用来控制和管理进程,如:创建、终止、等待、查看状态等。
2.1 创建进程
在UNIX系统中,创建新进程的唯一方法是使用fork()函数。fork()函数会创建一个新的进程,这个新的进程是原进程的副本。新的进程(子进程)获得与原进程(父进程)几乎相同的地址空间。
以下是一个简单的fork()函数示例:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  

  4. int main() {  
  5.     pid_t pid;  
  6.     pid = fork(); //创建一个新进程  
  7.     if (pid < 0) { //如果fork失败  
  8.         fprintf(stderr, "Fork failed.\n");  
  9.         exit(-1);  
  10.     } else if (pid == 0) { //子进程  
  11.         printf("I am the child, my pid is %d and my parent's pid is %d.\n", getpid(), getppid());  
  12.     } else { //父进程  
  13.         printf("I am the parent, my pid is %d and my child's pid is %d.\n", getpid(), pid);  
  14.     }  
  15.     return 0;  
  16. }
复制代码
2.2 终止进程
在UNIX系统中,有多种方法可以用来终止进程,如:exit()、_exit()、kill()等。exit()和_exit()函数用于自愿终止进程,而kill()函数用于非自愿终止进程。
以下是一个简单的kill()函数示例:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <signal.h>  

  5. int main() {  
  6.     pid_t pid;  
  7.     pid = fork(); //创建一个新进程  
  8.     if (pid < 0) { //如果fork失败  
  9.         fprintf(stderr, "Fork failed.\n");  
  10.         exit(-1);  
  11.     } else if (pid == 0) { //子进程  
  12.         printf("I am the child, my pid is %d and my parent's pid is %d.\n", getpid(), getppid());  
  13.         kill(getppid(), SIGKILL); //杀死父进程  
  14.     } else { //父进程  
  15.         printf("I am the parent, my pid is %d and my child's pid is %d.\n", getpid(), pid);  
  16.     }  
  17.     return 0;  
  18. }
复制代码
2.3 等待进程
在UNIX系统中,父进程可以使用wait()或waitpid()函数来等待子进程的终止。这种等待让父进程可以获取子进程的退出状态,同时也可以让父进程避免产生僵尸进程。
以下是一个简单的waitpid()函数示例:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/wait.h>  
  5. #include <signal.h>  

  6. int main() {  
  7.     pid_t pid;  
  8.     int status;  
  9.     pid = fork(); //创建一个新进程  
  10.     if (pid < 0) { //如果fork失败  
  11.         fprintf(stderr, "Fork failed.\n");  
  12.         exit(-1);  
  13.     } else if (pid == 0) { //子进程  
  14.         printf("I am the child, my pid is %d and my parent's pid is %d.\n", getpid(), getppid());  
  15.         kill(getppid(), SIGKILL); //杀死父进程  
  16.     } else { //父进程  
  17.         printf("I am the parent, my pid is %d and my child's pid is %d.\n", getpid(), pid);  
  18.         waitpid(pid, &status, 0); //等待子进程结束并获取退出状态  
  19.         printf("Child exited with status %d.\n", status); //输出子进程的退出状态  
  20.     }  
  21.     return 0;  
  22. }
复制代码
2.4 查看进程状态
在UNIX环境下,我们可以使用ps命令或者getprocs函数来查看进程的状态。
2.4.1 使用ps命令
ps命令可以用来查看系统中当前运行的进程状态。例如,可以使用以下命令查看所有进程:
  1. ps aux
复制代码
这将显示所有用户的所有进程的详细信息,包括进程ID、CPU使用率、内存使用情况等。
2.4.2 使用getprocs函数
在C语言中,我们可以使用getprocs函数来获取系统中的进程信息。getprocs函数会返回一个包含所有进程的结构体数组。
以下是一个简单的示例程序,演示如何使用getprocs函数:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/sysctl.h>  
  5. #include <structproc.h>  
  6.   
  7. int main() {  
  8.     int numprocs;  
  9.     struct proc_struct *procs;  
  10.     numprocs = sysctl(1, 0, 0); //获取系统中的进程数  
  11.     procs = malloc(numprocs * sizeof(struct proc_struct)); //分配内存空间  
  12.     getprocs(procs, numprocs, 0, 0); //获取进程信息  
  13.     for(int i = 0; i < numprocs; i++) {  
  14.         printf("Process %d: %s\n", procs[i].p_pid, procs[i].p_comm); //输出进程ID和进程名称  
  15.     }  
  16.     free(procs); //释放内存空间  
  17.     return 0;  
  18. }
复制代码
3. 进阶进程管理
除了上述基本的进程管理方法,UNIX和类UNIX系统还提供了一些更高级的进程管理功能,如线程创建和管理、进程组、会话、信号处理等。这些功能可以极大地满足复杂应用程序的进程管理需求。
3.1 线程创建和管理在UNIX和类UNIX系统中,线程是进程的基本执行单元。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、打开的文件和网络连接等。
要创建一个线程,可以使用pthread_create函数。该函数接受一个指向线程属性结构体的指针、一个指向线程函数的指针和一个指向传递给线程函数的参数的指针。例如:
  1. #include <pthread.h>  
  2.   
  3. void *my_thread_func(void *arg) {  
  4.     // 线程函数的代码  
  5.     return NULL;  
  6. }  
  7.   
  8. int main() {  
  9.     pthread_t my_thread;  
  10.     int ret = pthread_create(&my_thread, NULL, my_thread_func, NULL);  
  11.     if (ret != 0) {  
  12.         // 线程创建失败的处理代码  
  13.         return 1;  
  14.     }  
  15.     // 等待线程结束的代码  
  16.     pthread_join(my_thread, NULL);  
  17.     return 0;  
  18. }
复制代码
3.2 进程组进程组是一组相关进程的集合。在UNIX和类UNIX系统中,进程组由一个进程组ID(PGID)标识。进程可以通过调用setpgid函数将自己加入到一个已有的进程组中,或者创建一个新的进程组。进程组的创建者称为进程组组长(PGID为0),可以调用setpgid函数将自己设置为进程组组长。进程组组长可以调用setpgid函数将自己的PGID传递给其他进程,使其成为新的进程组组长。
进程组组长可以调用killpg函数向整个进程组发送信号。例如,要向一个进程组发送一个SIGTERM信号,可以使用以下代码:
  1. #include <signal.h>  
  2. #include <unistd.h>  
  3. #include <stdio.h>  
  4.   
  5. int main() {  
  6.     pid_t pgid = getpgid(0); // 获取当前进程的PGID  
  7.     killpg(pgid, SIGTERM);  // 向整个进程组发送SIGTERM信号  
  8.     printf("Sent SIGTERM to process group %d\n", pgid);  
  9.     return 0;  
  10. }<b>
  11. </b>
复制代码
3.3 会话会话是一组相关进程的集合,由一个会话ID(SID)标识。在UNIX和类UNIX系统中,会话的创建者称为会话领导(SID为0),可以调用setsid函数将自己设置为会话领导。会话领导可以调用setsid函数将自己的SID传递给其他进程,使其成为新的会话领导。会话领导可以调用killpg函数向整个会话发送信号。
3.4 信号处理
信号是UNIX和类UNIX系统用于进程间通信的一种机制。信号是一段二进制数据,可以携带有关事件的信息(例如,进程终止、挂起、就绪等)。进程可以接收、处理和发送信号。
在UNIX和类UNIX系统中,有三种类型的信号:

  •     实时信号(可被捕获并处理):例如,SIGINT(对应键盘中断)和SIGTERM(对应进程终止)。
  •     不可靠信号(可能会被忽略或丢失):例如,SIGSTOP(对应停止进程)和SIGKILL(对应终止进程)。
  •     可靠信号:一种进程可以请求系统在某个未来时间点发送的信号。
处理信号的常见方法包括:

  •     使用signal函数注册信号处理程序:signal(int signum, void (*func)(int))。当signum指定的信号发生时,系统将调用func函数。
  •     使用raise函数发送信号给当前进程:raise(int signum)。
  •     使用kill函数发送信号给指定进程:kill(pid_t pid, int signum)。
  •     使用waitpid、wait或类似的函数等待子进程终止,并获取其状态信息。
注意,在使用信号时需要注意以下问题:

  •     同一进程只能对每个信号有一个处理程序。
  •     在多线程环境中,需要注意信号处理函数的线程安全性。
  •     在信号处理函数中调用某些库函数可能会不安全,因为这些函数可能不是异步信号安全的。
  •     信号的发送和接收可能会受到进程的实际用户和组ID的限制。
以上就是UNIX和类UNIX系统的进程管理高级功能。这些功能可以使复杂的应用程序更好地管理其进程资源。




4. 进程间通信
在UNIX环境中,有多种方式可以让进程之间进行数据交换,这些方式被称为进程间通信(IPC)。下面介绍几种常见的IPC方式:
4.1 管道
管道(pipe)是一种最简单的进程间通信方式,它可以让一个进程的输出直接成为另一个进程的输入。管道通常用于父子进程之间的通信。
以下是一个使用管道的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4.   
  5. int main() {  
  6.     int pipefd[2];  
  7.     pid_t pid;  
  8.     char buf[1024];  
  9.   
  10.     if (pipe(pipefd) == -1) {  
  11.         perror("pipe");  
  12.         exit(-1);  
  13.     }  
  14.       
  15.     pid = fork();  
  16.     if (pid == -1) {  
  17.         perror("fork");  
  18.         exit(-1);  
  19.     } else if (pid == 0) { // 子进程  
  20.         close(pipefd[1]); // 关闭管道的写端  
  21.         read(pipefd[0], buf, sizeof(buf));  
  22.         printf("Child process received message: %s\n", buf);  
  23.         close(pipefd[0]);  
  24.     } else { // 父进程  
  25.         close(pipefd[0]); // 关闭管道的读端  
  26.         write(pipefd[1], "Hello from parent", 17);  
  27.         close(pipefd[1]);  
  28.     }  
  29.     return 0;  
  30. }
复制代码
要管理线程,可以使用pthread_join函数等待线程结束,使用pthread_exit函数从线程中退出,使用pthread_cancel函数取消线程等。这些函数的用法与上述函数类似。

4.2 命名管道
命名管道(named pipe)是管道的一种扩展,它允许无亲缘关系进程间的通信。命名管道通常在文件系统中以特殊文件形式存在,类似于普通文件。
4.3 信号
信号(signal)是一种可以由一个进程发送给另一个进程的软件中断,用于通知对方某个事件已经发生或者请求响应。例如,当用户按下Ctrl+C时,系统会向当前前景进程发送SIGINT信号。
以下是一个使用信号的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <signal.h>  
  4. #include <unistd.h>  
  5.   
  6. void signal_handler(int signum) {  
  7.     printf("Received signal %d\n", signum);  
  8. }  
  9.   
  10. int main() {  
  11.     signal(SIGINT, signal_handler); // 注册信号处理函数  
  12.     while(1) {  
  13.         printf("Waiting for signal...\n");  
  14.         sleep(1);  
  15.     }  
  16.     return 0;  
  17. }
复制代码
4.4 共享内存
共享内存是一种高效的进程间通信方式,它允许不同进程访问同一块物理内存空间。共享内存允许多个进程之间快速交换数据,并且可以避免复制数据的开销。
以下是一个使用共享内存的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/ipc.h>  
  5. #include <sys/shm.h>  
  6.   
  7. #define SHM_SIZE 1024  
  8.   
  9. int main() {  
  10.     int shmid;  
  11.     key_t key;  
  12.     char *shm, *s;  
  13.     pid_t pid;  
  14.   
  15.     key = 9876;  
  16.     shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);  
  17.     if (shmid < 0) {  
  18.         perror("shmget");  
  19.         exit(-1);  
  20.     }  
  21.   
  22.     shm = shmat(shmid, NULL, 0);  
  23.     if (shm == (char *) -1) {  
  24.         perror("shmat");  
  25.         exit(-1);  
  26.     }  
  27.   
  28.     // 在共享内存中写入数据  
  29.     s = shm;  
  30.     for (char c = 'a'; c <= 'z'; c++) {  
  31.         *s++ = c;  
  32.     }  
  33.     *s = '\0';  
  34.   
  35.     // 创建子进程,并等待子进程结束  
  36.     pid = fork();  
  37.     if (pid == -1) {  
  38.         perror("fork");  
  39.         exit(-1);  
  40.     } else if (pid == 0) { // 子进程  
  41.         // 在共享内存中读取数据  
  42.         printf("Child process read message: %s\n", shm);  
  43.         exit(0);  
  44.     } else { // 父进程  
  45.         wait(NULL);  
  46.         printf("Parent process read message: %s\n", shm);  
  47.     }  
  48.   
  49.     // 分离共享内存并删除共享内存标识符  
  50.     shmdt(shm);  
  51.     shmctl(shmid, IPC_RMID, NULL);  
  52.     return 0;  
  53. }
复制代码
4.5 消息队列
消息队列是一种高级的进程间通信方式,它允许不同进程之间以消息的形式进行数据交换。消息队列具有优先级、容量限制和持久性等特性。
  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <unistd.h>   
  4. #include <sys/ipc.h>   
  5. #include <sys/msg.h>   
  6. #include <string.h>   
  7.   
  8. #define MSG_SIZE 1024   
  9. #define QUEUE_SIZE 1000000  // 设置队列容量为10M,可根据实际情况调整容量大小。  
  10.   
  11. // 消息结构体  
  12. struct msg_buffer {  
  13.     long mtype;  
  14.     char mtext[MSG_SIZE];  
  15. };  
  16.   
  17. int main() {  
  18.     key_t key;  
  19.     int msg_id;  
  20.     struct msg_buffer send_msg, recv_msg;  
  21.       
  22.     // 生成唯一的键,用于创建或打开消息队列  
  23.     if ((key = ftok("/tmp", 'R')) == -1) {  
  24.         perror("ftok");  
  25.         exit(1);  
  26.     }  
  27.       
  28.     // 创建或打开消息队列  
  29.     if ((msg_id = msgget(key, IPC_CREAT | 0666)) == -1) {  
  30.         perror("msgget");  
  31.         exit(1);  
  32.     }  
  33.       
  34.     // 发送消息  
  35.     send_msg.mtype = 1; // 消息类型  
  36.     strcpy(send_msg.mtext, "Hello from sender!"); // 消息内容  
  37.     if (msgsnd(msg_id, &send_msg, MSG_SIZE, 0) == -1) {  
  38.         perror("msgsnd");  
  39.         exit(1);  
  40.     }  
  41.     printf("Message sent: %s\n", send_msg.mtext);  
  42.       
  43.     // 接收消息  
  44.     if (msgrcv(msg_id, &recv_msg, MSG_SIZE, 1, 0) == -1) {  
  45.         perror("msgrcv");  
  46.         exit(1);  
  47.     }  
  48.     printf("Message received: %s\n", recv_msg.mtext);  
  49.       
  50.     // 删除消息队列  
  51.     if (msgctl(msg_id, IPC_RMID, 0) == -1) {  
  52.         perror("msgctl");  
  53.         exit(1);  
  54.     }  
  55.     return 0;  
  56. }
复制代码
4.6 信号量
信号量是一种同步机制,用于控制多个进程对共享资源的访问。信号量可以是二进制信号量或计数信号量。
以下是一个使用二进制信号量的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/ipc.h>  
  5. #include <sys/sem.h>  
  6.   
  7. #define SEM_SIZE 1000  // 设置信号量大小为1000,可根据实际情况调整容量大小。  
  8.   
  9. int main() {  
  10.     int semid;  
  11.     key_t key;  
  12.     struct sembuf sops;  
  13.     int semval;  
  14.   
  15.     key = 9876;  
  16.     semid = semget(key, 1, IPC_CREAT | 0666);  // 创建信号量标识符  
  17.     if (semid < 0) {  
  18.         perror("semget");  
  19.         exit(-1);  
  20.     }  
  21.   
  22.     sops.sem_num = 0;  // 操作号  
  23.     sops.sem_op = -1;  // 减操作,减少一个信号量  
  24.     sops.sem_flg = SEM_UNDO;  // 自动释放信号量  
  25.     semval = semctl(semid, 0, GETVAL);  // 获取信号量初始值  
  26.     if (semval < 0) {  
  27.         perror("semctl");  
  28.         exit(-1);  
  29.     }  
  30.   
  31.     printf("Semaphore initial value = %d\n", semval);  // 输出信号量初始值  
  32.   
  33.     sops.sem_op = 1;  // 加操作,增加一个信号量  
  34.     sops.sem_flg = SEM_UNDO;  // 自动释放信号量  
  35.     semctl(semid, 0, SETVAL, semval + 1);  // 设置信号量值为初始值+1  
  36.     if (semctl(semid, 0, GETVAL) != semval + 1) {  // 获取更新后的信号量值,验证操作是否成功  
  37.         perror("semctl");  
  38.         exit(-1);  
  39.     }  
  40.   
  41.     printf("Semaphore updated value = %d\n", semctl(semid, 0, GETVAL));  // 输出更新后的信号量
  42. }
复制代码
4.6.1 计数信号量
计数信号量是一种特殊的信号量,它用于限制访问共享资源的最大并发进程数。计数信号量的值表示当前允许访问共享资源的进程数。当一个进程访问共享资源时,计数信号量的值减1;当一个进程释放共享资源时,计数信号量的值加1。
以下是一个使用计数信号量的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/ipc.h>  
  5. #include <sys/sem.h>  
  6.   
  7. #define SEM_SIZE 10  // 设置信号量大小为10,可根据实际情况调整容量大小。  
  8.   
  9. int main() {  
  10.     int semid;  
  11.     key_t key;  
  12.     struct sembuf sops;  
  13.     int semval;  
  14.   
  15.     key = 9876;  
  16.     semid = semget(key, SEM_SIZE, IPC_CREAT | 0666);  // 创建信号量标识符  
  17.     if (semid < 0) {  
  18.         perror("semget");  
  19.         exit(-1);  
  20.     }  
  21.   
  22.     for (int i = 0; i < SEM_SIZE; i++) {  // 初始化信号量值为SEM_SIZE  
  23.         sops.sem_num = i;  // 操作号  
  24.         sops.sem_op = 1;  // 加操作,增加一个信号量  
  25.         sops.sem_flg = SEM_UNDO;  // 自动释放信号量  
  26.         semctl(semid, i, SETVAL, SEM_SIZE - i);  // 设置信号量值为SEM_SIZE - i  
  27.     }  
  28.   
  29.     for (int i = 0; i < SEM_SIZE; i++) {  // 循环减少信号量值,表示当前允许访问的进程数  
  30.         sops.sem_num = i;  // 操作号  
  31.         sops.sem_op = -1;  // 减操作,减少一个信号量  
  32.         sops.sem_flg = SEM_UNDO;  // 自动释放信号量  
  33.         semctl(semid, i, SEM_UNDO, sops);  // 执行减操作  
  34.     }
  35. }
复制代码
4.6.2 进程组和会话
进程组和会话是UNIX系统中进程的两种重要组织形式。进程组是对一组进程的抽象,它们共享相同的PID(进程ID)。会话则是一组进程组的集合,这些进程组共享相同的会话领导(会话组长)。会话组长拥有对会话的控制权,如挂起、恢复等。
以下是一个使用进程组和会话的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/types.h>  
  5. #include <sys/ipc.h>  
  6. #include <sys/sem.h>  
  7.   
  8. #define SEM_SIZE 10  // 设置信号量大小为10,可根据实际情况调整容量大小。  
  9.   
  10. int main() {  
  11.     int semid, pid, pgid;  
  12.     key_t key;  
  13.     struct sembuf sops;  
  14.     int semval;  
  15.   
  16.     key = 9876;  
  17.     semid = semget(key, SEM_SIZE, IPC_CREAT | 0666);  // 创建信号量标识符  
  18.     if (semid < 0) {  
  19.         perror("semget");  
  20.         exit(-1);  
  21.     }  
  22.   
  23.     pid = getpid();  // 获取当前进程的PID  
  24.     pgid = getpgrp();  // 获取当前进程的进程组ID  
  25.   
  26.     printf("Current process ID: %d\n", pid);  // 输出当前进程的PID  
  27.     printf("Current process group ID: %d\n", pgid);  // 输出当前进程的进程组ID
  28. }
复制代码
4.6.3 共享内存
共享内存允许多个进程访问同一块物理内存空间,从而避免了数据的复制,因此效率很高。多个进程可以通过共享内存来共享数据,通常用于实现多进程之间的信息共享、协调同步等。
以下是一个使用共享内存的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/ipc.h>  
  5. #include <sys/shm.h>  
  6.   
  7. #define SHM_SIZE 1024  // 设置共享内存大小为1024字节,可根据实际情况调整容量大小。  
  8.   
  9. int main() {  
  10.     int shmid;  
  11.     key_t key;  
  12.     char *shm, *s;  
  13.     pid_t pid;  
  14.   
  15.     key = 9876;  
  16.     shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);  // 创建共享内存标识符  
  17.     if (shmid < 0) {  
  18.         perror("shmget");  
  19.         exit(-1);  
  20.     }  
  21.   
  22.     shm = shmat(shmid, NULL, 0);  // 附加到共享内存  
  23.     if (shm == (char *) -1) {  
  24.         perror("shmat");  
  25.         exit(-1);  
  26.     }  
  27.   
  28.     // 在共享内存中写入数据  
  29.     s = shm;  
  30.     for (char c = 'a'; c <= 'z'; c++) {  
  31.         *s++ = c;  
  32.     }  
  33.     *s = '\0';  
  34.   
  35.     // 创建子进程,并等待子进程结束  
  36.     pid = fork();  
  37.     if (pid == -1) {  
  38.         perror("fork");  
  39.         exit(-1);  
  40.     } else if (pid == 0) { // 子进程  
  41.         // 在共享内存中读取数据  
  42.         printf("Child process read message: %s\n", shm);  
  43.         exit(0);  
  44.     } else { // 父进程  
  45.         wait(NULL);  // 等待子进程结束  
  46.         printf("Parent process read message: %s\n", shm);  
  47.     }  
  48.   
  49.     // 分离共享内存并删除共享内存标识符  
  50.     shmdt(shm);  
  51.     shmctl(shmid, IPC_RMID, NULL);  
  52.     return 0;  
  53. }
复制代码
4.6.4 信号
信号是一种软件中断,用于通知进程发生了某个事件。进程可以通过捕获信号、执行相应的处理程序(信号处理函数)来响应信号。常见的信号包括 SIGINT(中断信号)、SIGTERM(终止信号)等。
以下是一个使用信号的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <signal.h>  
  4. #include <unistd.h>  
  5.   
  6. #define SIG_NUM 1  
  7.   
  8. void handle_signal(int signo) {  
  9.     printf("Received signal %d\n", signo);  
  10.     exit(0);  
  11. }  
  12.   
  13. int main() {  
  14.     struct sigaction sa;  
  15.     sa.sa_handler = handle_signal;  
  16.     sigemptyset(&sa.sa_mask);  
  17.     sa.sa_flags = 0;  
  18.     if (sigaction(SIG_NUM, &sa, NULL) == -1) {  
  19.         perror("sigaction");  
  20.         exit(-1);  
  21.     }  
  22.     printf("Sending signal to self\n");  
  23.     kill(getpid(), SIG_NUM);  
  24.     return 0;  
  25. }
复制代码
在这个示例程序中,我们首先定义了一个 handle_signal 函数,用于处理收到的信号。接着,在 main 函数中,我们使用 sigaction 函数注册了一个信号处理程序(即 handle_signal 函数),并使用 kill 函数向自身发送一个信号(即 SIG_NUM 信号)。当接收到该信号时,就会执行 handle_signal 函数,并输出一条消息后退出程序。
4.6.5 文件锁
文件锁是一种机制,用于在并发访问文件时防止数据竞争或不一致状态。文件锁允许进程或线程对文件进行加锁,以实现对文件的独占访问或同步访问。
以下是一个使用文件锁的简单示例程序:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <fcntl.h>  
  4. #include <unistd.h>  
  5. #include <sys/file.h>  
  6.   
  7. #define FILENAME "/tmp/lock_file"  
  8.   
  9. int main() {  
  10.     int fd;  
  11.     fd = open(FILENAME, O_WRONLY | O_CREAT, 0666);  // 打开或创建文件  
  12.     if (fd == -1) {  
  13.         perror("open");  
  14.         exit(-1);  
  15.     }  
  16.     if (flock(fd, LOCK_EX) == -1) {  // 对文件加独占锁  
  17.         perror("flock");  
  18.         exit(-1);  
  19.     }  
  20.     printf("Acquired lock on file %s\n", FILENAME);  
  21.     sleep(5);  // 模拟进程休眠时间  
  22.     printf("releasing lock\n");  
  23.     if (flock(fd, LOCK_UN) == -1) {  // 释放锁  
  24.         perror("flock");  
  25.         exit(-1);  
  26.     }  
  27.     close(fd);  // 关闭文件  
  28.     return 0;  
  29. }
复制代码
在这个示例程序中,我们使用了 flock 函数对文件进行加锁和解锁操作。首先,我们打开或创建了一个名为 /tmp/lock_file 的文件,并使用 flock 函数对该文件加上了独占锁。然后,模拟进程休眠一段时间(以便其他进程有机会尝试对文件加锁),最后释放文件锁,并关闭文件。


──── 0人觉得很赞 ────

使用道具 举报

2023-9-14 16:48:58
字多可能有手误,欢迎指正
2023-9-14 22:17:15
第一次认识到unix,学习一下
2023-9-15 08:38:24
那么怎么在电脑上装一个Unix的系统呢?有镜像连接吗?
2023-9-15 09:17:10
学习
2023-9-15 09:32:22
ckdsx.cn 发表于 2023-9-15 08:38
那么怎么在电脑上装一个Unix的系统呢?有镜像连接吗?

我没找到unix的镜像,但是有一个类unix系统,安装方式如下链接:https://blog.csdn.net/Wantfly995 ... 59214-null-null.142^v94^chatsearchT3_1&utm_term=unix%E9%95%9C%E5%83%8F&spm=1018.2226.3001.4187
2023-9-15 09:43:33
谢谢,再问一下,使用unix能给我们带来什么优势?相较于win或Linux,?
2023-9-15 10:08:50
打卡学习
2023-9-15 10:22:47
ckdsx.cn 发表于 2023-9-15 09:43
谢谢,再问一下,使用unix能给我们带来什么优势?相较于win或Linux,?

高度稳定和可靠:Unix和Linux都是高度稳定和可靠的操作系统,但是,unix在服务器端和工作站领域,表现得更为出色。
丰富的网络功能:Unix系统是互联网技术和异种机连接的重要手段,很多网络通信协议都是在Unix系统上开发和发展起来的,例如TCP/IP。由于Unix系统为各种网络通信协议提供了良好的支持,综合下来使得Unix服务器在Internet服务器中占80%以上,占据绝对优势。
多用户多任务环境Unix和Linux都是多用户多任务操作系统,但它们实现多任务的方式有所不同。Unix通过给紧急任务分配较高优先级来处理多任务,而Linux则通过充分利用CPU的任务切换机制来实现多任务处理,他们的支持的多用户数量上限取决于计算机硬件的能力和配置,然后,win是单用户多任务模式。

但是随着未来技术的发展和积累,这些界限和优势可能会逐渐变得模糊。


2023-9-15 10:31:28
沙发自己的沙发
您需要登录后才可以回帖 立即登录
高级模式
12下一页
统计信息
  • 会员数: 28101 个
  • 话题数: 39325 篇