用C给出一个基于优先级的互斥信号量的实现,给出使用它的例子,并给出源码和注释
时间: 2023-05-31 13:05:13 浏览: 102
microC/OSII 互斥和信号量的例子,有代码
以下是基于优先级的互斥信号量的实现,使用了链表来维护等待队列。同时给出了一个使用它的例子。
mutex.h:
```c
#ifndef MUTEX_H
#define MUTEX_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define MAX_PRIORITY 10
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
typedef struct mutex_t {
int sem_id;
int wait_count[MAX_PRIORITY];
struct node_t *wait_queue[MAX_PRIORITY];
} mutex_t;
typedef struct node_t {
int pid;
int priority;
struct node_t *next;
} node_t;
int mutex_init(mutex_t *mutex);
int mutex_lock(mutex_t *mutex, int priority);
int mutex_unlock(mutex_t *mutex);
#endif
```
mutex.c:
```c
#include "mutex.h"
int mutex_init(mutex_t *mutex) {
int i;
key_t key;
union semun arg;
key = ftok(".", 'm');
mutex->sem_id = semget(key, 1, IPC_CREAT | 0666);
if (mutex->sem_id < 0) {
perror("semget error");
return -1;
}
arg.val = 1;
if (semctl(mutex->sem_id, 0, SETVAL, arg) < 0) {
perror("semctl error");
return -1;
}
for (i = 0; i < MAX_PRIORITY; i++) {
mutex->wait_count[i] = 0;
mutex->wait_queue[i] = NULL;
}
return 0;
}
int mutex_lock(mutex_t *mutex, int priority) {
struct sembuf sops;
node_t *node, *p;
sops.sem_num = 0;
sops.sem_op = -1;
sops.sem_flg = SEM_UNDO;
if (semop(mutex->sem_id, &sops, 1) < 0) {
perror("semop error");
return -1;
}
if (mutex->wait_count[priority] == 0) {
mutex->wait_count[priority]++;
return 0;
}
node = (node_t *)malloc(sizeof(node_t));
node->pid = getpid();
node->priority = priority;
node->next = NULL;
p = mutex->wait_queue[priority];
if (p == NULL) {
mutex->wait_queue[priority] = node;
} else {
while (p->next != NULL) {
p = p->next;
}
p->next = node;
}
mutex->wait_count[priority]++;
while (mutex->wait_queue[priority]->pid != getpid()) {
sops.sem_op = 1;
if (semop(mutex->sem_id, &sops, 1) < 0) {
perror("semop error");
return -1;
}
sleep(1);
sops.sem_op = -1;
if (semop(mutex->sem_id, &sops, 1) < 0) {
perror("semop error");
return -1;
}
}
return 0;
}
int mutex_unlock(mutex_t *mutex) {
struct sembuf sops;
node_t *node;
int i;
sops.sem_num = 0;
sops.sem_op = 1;
sops.sem_flg = SEM_UNDO;
if (semop(mutex->sem_id, &sops, 1) < 0) {
perror("semop error");
return -1;
}
for (i = 0; i < MAX_PRIORITY; i++) {
if (mutex->wait_count[i] > 0) {
mutex->wait_count[i]--;
node = mutex->wait_queue[i];
mutex->wait_queue[i] = node->next;
sops.sem_op = -1;
if (semop(mutex->sem_id, &sops, 1) < 0) {
perror("semop error");
return -1;
}
return 0;
}
}
return 0;
}
```
main.c:
```c
#include "mutex.h"
int main() {
mutex_t mutex;
int i, j;
mutex_init(&mutex);
for (i = 0; i < MAX_PRIORITY; i++) {
for (j = 0; j < 3; j++) {
if (fork() == 0) {
mutex_lock(&mutex, i);
printf("pid=%d priority=%d\n", getpid(), i);
sleep(1);
mutex_unlock(&mutex);
exit(0);
}
}
}
while (wait(NULL) != -1);
return 0;
}
```
使用该互斥信号量的例子是创建了30个进程,分别有10个进程优先级为0,10个进程优先级为1,10个进程优先级为2。每个进程都会先等待一段时间再输出自己的pid和优先级,然后再等待一段时间再释放锁。这样就可以测试出优先级的效果。
源码中使用了链表来维护等待队列,每个节点保存了等待进程的pid和优先级。在加锁时,如果当前优先级没有等待进程,则直接返回;否则将当前进程加入到对应的等待队列中。在解锁时,从高优先级到低优先级遍历等待队列,如果某个队列中有等待进程,则唤醒该队列中的第一个进程并返回。如果所有队列都没有等待进程,则直接返回。
注意,由于本例中使用了链表,所以在释放锁的时候需要使用semop函数来先将信号量加1,以便等待队列中的进程能够从信号量阻塞中唤醒。同时,为了避免死锁,加锁时需要在等待队列中等待期间释放信号量,让其他进程能够获取锁。
阅读全文