69天探索操作系统-第42天:资源分配图论

442 阅读5分钟
pro8.avif

1. 介绍

资源分配图(RAG) 是一种图形和数学工具,用于表示系统中资源分配给进程的情况。它们特别有助于检测和预防死锁,死锁发生在进程因等待其他进程持有的资源而被阻塞时。

image.png

  • 过程: 在图中表示为圆圈。
  • 资源: 在图中表示为正方形。
  • 请求边: 从过程指向资源的定向边,表示一个过程正在请求一个资源。
  • 分配边: 从资源指向过程的定向边,表示一个资源当前分配给一个过程。

2. 图的组件和表示

资源分配图可以使用矩阵和数据结构在代码中表示。下面是C语言中实现的基本RAG结构:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAX_PROCESSES 100
#define MAX_RESOURCES 100

typedef struct {
    int process_id;
    int resource_id;
    int instances;
} Edge;

typedef struct {
    int num_processes;
    int num_resources;
    int **allocation_matrix;    // Current allocations
    int **request_matrix;       // Resource requests
    int *available_resources;   // Available instances
    int *max_resources;         // Maximum instances
} ResourceGraph;

ResourceGraph* create_resource_graph(int num_processes, int num_resources) {
    ResourceGraph *graph = malloc(sizeof(ResourceGraph));
    graph->num_processes = num_processes;
    graph->num_resources = num_resources;

    // Initialize allocation matrix
    graph->allocation_matrix = malloc(num_processes * sizeof(int*));
    for (int i = 0; i < num_processes; i++) {
        graph->allocation_matrix[i] = calloc(num_resources, sizeof(int));
    }

    // Initialize request matrix
    graph->request_matrix = malloc(num_processes * sizeof(int*));
    for (int i = 0; i < num_processes; i++) {
        graph->request_matrix[i] = calloc(num_resources, sizeof(int));
    }

    // Initialize resource vectors
    graph->available_resources = calloc(num_resources, sizeof(int));
    graph->max_resources = calloc(num_resources, sizeof(int));

    return graph;
}

3. 使用RAG进行死锁检测

死锁检测涉及识别资源分配图中的循环。如果存在循环,则表明发生了死锁。

死锁检测算法

以下是死锁检测算法的实现:

typedef struct {
    bool *marked;
    int num_processes;
    ResourceGraph *graph;
} DeadlockDetector;

bool is_process_finished(DeadlockDetector *detector, int process_id) {
    for (int r = 0; r < detector->graph->num_resources; r++) {
        if (detector->graph->request_matrix[process_id][r] >
            detector->graph->available_resources[r]) {
            return false;
        }
    }
    return true;
}

bool detect_deadlock(ResourceGraph *graph) {
    DeadlockDetector detector = {
        .marked = calloc(graph->num_processes, sizeof(bool)),
        .num_processes = graph->num_processes,
        .graph = graph
    };

    bool progress;
    do {
        progress = false;
        for (int p = 0; p < graph->num_processes; p++) {
            if (!detector.marked[p] && is_process_finished(&detector, p)) {
                detector.marked[p] = true;
                progress = true;

                // Release resources
                for (int r = 0; r < graph->num_resources; r++) {
                    graph->available_resources[r] +=
                        graph->allocation_matrix[p][r];
                }
            }
        }
    } while (progress);

    // Check for unmarked processes (deadlocked)
    bool deadlock = false;
    for (int p = 0; p < graph->num_processes; p++) {
        if (!detector.marked[p]) {
            deadlock = true;
            printf("Process %d is deadlocked\n", p);
        }
    }

    free(detector.marked);
    return deadlock;
}

4. 死锁预防策略

死锁预防涉及通过仔细管理资源分配来确保系统永远不会进入死锁状态。

死锁预防实现

以下是死锁预防机制的一个实现:

typedef struct {
    ResourceGraph *graph;
    int *process_priority;
    bool *resource_preemptable;
} DeadlockPrevention;

bool can_allocate_safely(DeadlockPrevention *dp,
                        int process_id,
                        int resource_id,
                        int requested_instances) {
    // Check if allocation would exceed maximum
    if (dp->graph->allocation_matrix[process_id][resource_id] +
        requested_instances > dp->graph->max_resources[resource_id]) {
        return false;
    }

    // Check if resources are available
    if (dp->graph->available_resources[resource_id] < requested_instances) {
        // Try preemption if possible
        if (dp->resource_preemptable[resource_id]) {
            return try_preemption(dp, process_id, resource_id,
                                requested_instances);
        }
        return false;
    }

    return true;
}

bool allocate_resources(DeadlockPrevention *dp,
                       int process_id,
                       int resource_id,
                       int instances) {
    if (!can_allocate_safely(dp, process_id, resource_id, instances)) {
        return false;
    }

    dp->graph->allocation_matrix[process_id][resource_id] += instances;
    dp->graph->available_resources[resource_id] -= instances;
    return true;
}

5. 循环检测算法

循环检测对于识别资源分配图中的死锁至关重要。

循环检测实现

以下是循环检测算法的实现:

typedef enum {
    WHITE,  // Not visited
    GRAY,   // Being visited
    BLACK   // Completed
} VertexColor;

typedef struct {
    VertexColor *colors;
    int *parent;
    ResourceGraph *graph;
} CycleDetector;

bool detect_cycle_util(CycleDetector *detector,
                      int process_id,
                      int *cycle_start) {
    detector->colors[process_id] = GRAY;

    // Check all resource requests
    for (int r = 0; r < detector->graph->num_resources; r++) {
        if (detector->graph->request_matrix[process_id][r] > 0) {
            // Find processes holding this resource
            for (int p = 0; p < detector->graph->num_processes; p++) {
                if (detector->graph->allocation_matrix[p][r] > 0) {
                    if (detector->colors[p] == GRAY) {
                        *cycle_start = p;
                        return true;
                    }

                    if (detector->colors[p] == WHITE) {
                        detector->parent[p] = process_id;
                        if (detect_cycle_util(detector, p, cycle_start)) {
                            return true;
                        }
                    }
                }
            }
        }
    }

    detector->colors[process_id] = BLACK;
    return false;
}

代码解释

  1. CycleDetector 结构:CycleDetector 结构用于跟踪顶点颜色和父指针。
  2. 循环检测:detect_cycle_util() 函数使用深度优先搜索 (DFS) 来检测图中的循环。

6. 资源请求算法

银行家算法是一种资源分配和死锁避免算法,确保系统保持安全状态。

银行家算法实现

以下是银行家算法的实现:

typedef struct {
    int *work;
    bool *finish;
    int **need;
    ResourceGraph *graph;
} BankerAlgorithm;

bool is_safe_state(BankerAlgorithm *banker) {
    int num_p = banker->graph->num_processes;
    int num_r = banker->graph->num_resources;

    // Initialize work and finish arrays
    memcpy(banker->work, banker->graph->available_resources,
           num_r * sizeof(int));
    memset(banker->finish, false, num_p * sizeof(bool));

    bool found;
    do {
        found = false;
        for (int p = 0; p < num_p; p++) {
            if (!banker->finish[p]) {
                bool can_allocate = true;
                for (int r = 0; r < num_r; r++) {
                    if (banker->need[p][r] > banker->work[r]) {
                        can_allocate = false;
                        break;
                    }
                }

                if (can_allocate) {
                    for (int r = 0; r < num_r; r++) {
                        banker->work[r] +=
                            banker->graph->allocation_matrix[p][r];
                    }
                    banker->finish[p] = true;
                    found = true;
                }
            }
        }
    } while (found);

    // Check if all processes finished
    for (int p = 0; p < num_p; p++) {
        if (!banker->finish[p]) return false;
    }
    return true;
}

7. 图分析工具

图分析工具有助于理解资源利用和竞争。

图分析实现

以下是图分析工具的实现:

typedef struct {
    int *resource_utilization;
    int *process_waiting_time;
    int *resource_contention;
} GraphAnalytics;

void analyze_resource_utilization(ResourceGraph *graph,
                                GraphAnalytics *analytics) {
    for (int r = 0; r < graph->num_resources; r++) {
        int allocated = 0;
        for (int p = 0; p < graph->num_processes; p++) {
            allocated += graph->allocation_matrix[p][r];
        }
        analytics->resource_utilization[r] =
            (allocated * 100) / graph->max_resources[r];
    }
}

void analyze_resource_contention(ResourceGraph *graph,
                               GraphAnalytics *analytics) {
    for (int r = 0; r < graph->num_resources; r++) {
        int requesters = 0;
        for (int p = 0; p < graph->num_processes; p++) {
            if (graph->request_matrix[p][r] > 0) {
                requesters++;
            }
        }
        analytics->resource_contention[r] = requesters;
    }
}

8. 性能考虑

RAG的关键性能指标包括:

  • 图分析时间复杂度 基本分析为O(P * R)。
  • 死锁检测开销 最坏情况下为O(P * R)。
  • 内存需求: 矩阵存储为O(P * R)。
  • 资源利用效率: 衡量资源使用的有效性。
  • 系统吞吐量影响: 衡量资源分配对系统性能的影响。

9. 结论

资源分配图论为理解和管理操作系统中资源分配提供了一个强大的框架。其可视化和数学表示有助于检测和预防死锁,同时确保高效地利用资源。