1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
| #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <errno.h> #include <string.h> #include <sys/wait.h>
// 信号量操作联合体 union semun { int val; struct semid_ds *buf; unsigned short *array; };
// P操作(等待/减1) int P(int semid, int sem_num) { struct sembuf sb; sb.sem_num = sem_num; sb.sem_op = -1; // P操作 sb.sem_flg = 0; return semop(semid, &sb, 1); }
// V操作(发送/加1) int V(int semid, int sem_num) { struct sembuf sb; sb.sem_num = sem_num; sb.sem_op = 1; // V操作 sb.sem_flg = 0; return semop(semid, &sb, 1); }
// 等待信号量为0 int wait_zero(int semid, int sem_num) { struct sembuf sb; sb.sem_num = sem_num; sb.sem_op = 0; sb.sem_flg = 0; return semop(semid, &sb, 1); }
int main() { key_t key; int semid; union semun arg; printf("=== Semop函数示例 ===\n"); // 创建信号量集 key = ftok(".", 'b'); if (key == -1) { perror("ftok失败"); exit(EXIT_FAILURE); } semid = semget(key, 2, 0666 | IPC_CREAT | IPC_EXCL); if (semid == -1) { if (errno == EEXIST) { // 如果已存在,先删除再创建 semid = semget(key, 2, 0666); semctl(semid, 0, IPC_RMID); semid = semget(key, 2, 0666 | IPC_CREAT | IPC_EXCL); } else { perror("semget失败"); exit(EXIT_FAILURE); } } if (semid == -1) { perror("创建信号量集失败"); exit(EXIT_FAILURE); } printf("成功创建信号量集,标识符: %d\n", semid); // 初始化信号量 // 信号量0:用于互斥,初始值为1(二进制信号量) // 信号量1:用于资源计数,初始值为3(表示有3个资源) unsigned short init_values[2] = {1, 3}; arg.array = init_values; if (semctl(semid, 0, SETALL, arg) == -1) { perror("初始化信号量失败"); semctl(semid, 0, IPC_RMID); exit(EXIT_FAILURE); } printf("信号量初始化完成\n"); printf(" 信号量0(互斥): %d\n", semctl(semid, 0, GETVAL)); printf(" 信号量1(资源): %d\n", semctl(semid, 1, GETVAL)); // 示例1: 基本的P/V操作 printf("\n示例1: 基本的P/V操作\n"); printf("操作前 - 信号量0: %d, 信号量1: %d\n", semctl(semid, 0, GETVAL), semctl(semid, 1, GETVAL)); // P操作获取互斥锁 printf("执行P操作获取互斥锁...\n"); if (P(semid, 0) == -1) { perror("P操作失败"); } else { printf("成功获取互斥锁\n"); printf("操作后 - 信号量0: %d, 信号量1: %d\n", semctl(semid, 0, GETVAL), semctl(semid, 1, GETVAL)); // V操作释放互斥锁 printf("执行V操作释放互斥锁...\n"); if (V(semid, 0) == -1) { perror("V操作失败"); } else { printf("成功释放互斥锁\n"); printf("操作后 - 信号量0: %d, 信号量1: %d\n", semctl(semid, 0, GETVAL), semctl(semid, 1, GETVAL)); } } // 示例2: 多进程同步演示 printf("\n示例2: 多进程同步演示\n"); pid_t pid = fork(); if (pid == -1) { perror("fork失败"); semctl(semid, 0, IPC_RMID); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程 printf("子进程 %d 开始执行\n", getpid()); // 模拟需要互斥访问的临界区 printf("子进程尝试获取互斥锁...\n"); if (P(semid, 0) == 0) { printf("子进程 %d 进入临界区\n", getpid()); printf("子进程在临界区工作2秒...\n"); sleep(2); printf("子进程 %d 离开临界区\n", getpid()); V(semid, 0); // 释放锁 } exit(EXIT_SUCCESS); } else { // 父进程 sleep(1); // 让子进程先运行 printf("父进程 %d 开始执行\n", getpid()); printf("父进程尝试获取互斥锁...\n"); if (P(semid, 0) == 0) { printf("父进程 %d 进入临界区\n", getpid()); printf("父进程在临界区工作2秒...\n"); sleep(2); printf("父进程 %d 离开临界区\n", getpid()); V(semid, 0); // 释放锁 } // 等待子进程结束 wait(NULL); } // 示例3: 资源计数信号量演示 printf("\n示例3: 资源计数信号量演示\n"); printf("当前可用资源数: %d\n", semctl(semid, 1, GETVAL)); // 模拟多个进程竞争资源 for (int i = 0; i < 4; i++) { pid = fork(); if (pid == 0) { // 子进程 printf("进程 %d 尝试获取资源...\n", getpid()); // P操作获取资源 if (P(semid, 1) == 0) { printf("进程 %d 成功获取资源,剩余资源: %d\n", getpid(), semctl(semid, 1, GETVAL)); // 使用资源 printf("进程 %d 使用资源2秒...\n", getpid()); sleep(2); // V操作释放资源 V(semid, 1); printf("进程 %d 释放资源,剩余资源: %d\n", getpid(), semctl(semid, 1, GETVAL)); } else { printf("进程 %d 获取资源失败\n", getpid()); } exit(EXIT_SUCCESS); } } // 等待所有子进程结束 for (int i = 0; i < 4; i++) { wait(NULL); } // 清理资源 printf("\n清理资源...\n"); if (semctl(semid, 0, IPC_RMID) == -1) { perror("删除信号量集失败"); } else { printf("成功删除信号量集\n"); } return 0; }
|