希赛考试网
首页 > 软考 > 软件设计师

用信号量机制表示下面的前趋图

希赛网 2024-01-04 14:14:48

信号量机制是操作系统中用于协调多个进程或线程之间访问共同资源的一种机制。在前趋图中,也需要考虑诸多进程或线程间的协调问题。因此,本文就以“用信号量机制表示下面的前趋图”为题,从多个角度进行分析,介绍如何使用信号量机制来协调前趋图中各进程或线程之间的执行顺序。

信号量机制

信号量机制是内核提供的一种进程同步构造,主要用于多个进程或线程之间的协调。它是一个整型变量,并有两个基本操作:wait()和signal()。wait()操作使信号量减1,如果减1后结果为负数,则进程或线程进入等待队列中;signal()操作使信号量加1,并唤醒等待队列中的进程或线程。

那么,如何利用信号量机制表示一个前趋图呢?

一、无循环前趋图

对于无循环前趋图,处理起来相对较为简单,因为它的依赖关系是一个单向的有向无环图(DAG)。因此,我们可以设定一个二维数组matrix[][]表示依赖关系。matrix[i][j]表示第i个进程或线程是否依赖于第j个进程或线程,如果依赖,那么matrix[i][j]的值为1,否则为0。

接下来,我们可以利用两个信号量:semaphore[]和mutex,其中semaphore[]表示每个进程或线程的信号量,mutex表示互斥信号量。

1、初始化semaphore[]信号量为0,表示当前进程或线程不可运行;

2、初始化mutex信号量为1,表示当前排他锁可用;

3、设置一个线程或进程的总数num_threads;

4、按照依赖关系,生成一个拓扑序列topo[]数组;

5、当进程或线程j需要执行时,它会等待所有前驱进程或线程的信号量变为1,然后它将它的semaphore[j]信号量设置为1,表示自己可运行;

6、当进程或线程j运行完后,它会将其semaphore[j]信号量设置为0;

7、释放等待进程或线程的mutex信号量。

代码实现如下:

```C

int num_threads = 5;

int matrix[num_threads][num_threads];

int topo[num_threads];

semaphore semaphore[num_threads] = {0};

mutex mutex = 1;

void topo_sort() {

int in_degree[num_threads] = {0};

for(int i=0; i

for(int j=0; j

in_degree[i] += matrix[j][i];

}

}

int k = 0;

while(k < num_threads) {

int i = 0;

while(i < num_threads && in_degree[i] != 0) {

i++;

}

semaphore[i] = 1;

topo[k++] = i;

in_degree[i] = -1;

for(int j=0; j

if(matrix[i][j] == 1) {

in_degree[j]--;

}

}

}

}

void process(int i) {

for(int j=0; j

if(matrix[i][j] == 1) {

wait(semaphore[j]);

}

}

signal(semaphore[i]);

// process i

signal(semaphore[i]);

signal(mutex);

}

int main() {

topo_sort();

for(int i=0; i

semaphore[i] = 0;

}

for(int i=0; i

wait(mutex);

process(topo[i]);

}

return 0;

}

```

二、有循环前趋图

有循环的前趋图比较复杂,因为循环的存在使得依赖关系不是单向的有向无环图,而是成环的。因此,我们需要使用一些特殊的技巧来解决这个问题。

一种常用的方法是使用信号量dual[]和负载量payload[]。在这种方法中,dual[i]表示依赖于进程或线程i的所有进程或线程的数量。负载量payload[i]则表示进程或线程i所承载的工作数量。使用这两个变量,我们就可以实现循环作业的处理。

1、初始化semaphore[]信号量为0,表示当前进程或线程不可运行;

2、初始化mutex信号量为1,表示当前排他锁可用;

3、设置一个线程或进程的总数num_threads;

4、按照依赖关系,生成一个拓扑序列topo[]数组;

5、对于所有非循环的进程或线程,将其dual[i]的值设为依赖于它的进程或线程的总数;

6、对于所有循环的进程或线程,将dual[i]设为0;

7、对于所有非循环的进程或线程i,当进程或线程j需要执行时,它会等待所有前驱进程或线程的信号量变为1,然后它将其semaphore[j]信号量设置为1,表示它可运行;

8、对于所有循环的进程或线程k,当进程或线程j需要执行时,如果k是j的前驱进程或线程,那么它会先等待所有其他依赖于j的进程或线程都执行完才会开始运行;

9、进程或线程j执行完后,如果i是j的后继进程或线程,而且i是循环进程或线程,那么就需要自减dual[i]和payload[i];如果dual[i]和payload[i]均为0,则表示所有依赖于i的进程或线程均已完成,此时将i的semaphore[i]和dual[i]均设为0;

10、释放等待进程或线程的mutex信号量。

代码实现如下:

```C

int num_threads = 5;

int matrix[num_threads][num_threads];

int topo[num_threads];

semaphore semaphore[num_threads] = {0};

semaphore dual[num_threads] = {0};

int payload[num_threads] = {0};

mutex mutex = 1;

void topo_sort() {

int in_degree[num_threads] = {0};

for(int i=0; i

for(int j=0; j

in_degree[i] += matrix[j][i];

}

}

int k = 0;

while(k < num_threads) {

int i = 0;

while(i < num_threads && in_degree[i] != 0) {

i++;

}

if(i == num_threads) {

for(int j=0; j

if(in_degree[j] != -1) {

i = j;

break;

}

}

}

semaphore[i] = 1;

topo[k++] = i;

in_degree[i] = -1;

for(int j=0; j

if(matrix[i][j] == 1) {

in_degree[j]--;

}

}

}

}

int is_cycle(int u, int v) {

if(u == v) {

return 1;

}

for(int i=0; i

if(matrix[u][i] == 1) {

if(is_cycle(i, v)) {

return 1;

}

}

}

return 0;

}

void process(int i) {

if(dual[i] > 0) {

int u = 0;

for(int j=0; j

if(matrix[j][i] == 1) {

u = j;

break;

}

}

for(int j=0; j

if(matrix[u][j] == 1) {

wait(semaphore[j]);

}

}

for(int j=0; j

if(matrix[u][j] == 1) {

signal(semaphore[j]);

}

}

}

for(int j=0; j

if(matrix[i][j] == 1) {

wait(semaphore[j]);

}

}

signal(dual[i]);

while(dual[i] > 0) {

if(payload[i] == 0) {

signal(dual[i]);

break;

} else {

// process i

payload[i]--;

}

}

for(int j=0; j

if(matrix[i][j] == 1) {

signal(semaphore[j]);

if(is_cycle(j, i)) {

dual[j]--;

payload[j]--;

if(dual[j] == 0 && payload[j] == 0) {

signal(dual[j]);

semaphore[j] = 0;

}

}

}

}

if(dual[i] == 0 && payload[i] == 0) {

semaphore[i] = 0;

}

signal(mutex);

}

int main() {

topo_sort();

for(int i=0; i

semaphore[i] = 0;

dual[i] = 0;

payload[i] = 0;

for(int j=0; j

if(matrix[i][j] == 1 && matrix[j][i] == 1) {

dual[i]++;

}

}

}

for(int i=0; i

for(int j=0; j

if(matrix[i][j] == 1 && matrix[j][i] == 1) {

matrix[i][j] = 0;

}

}

}

for(int i=0; i

wait(mutex);

payload[i] = 1;

process(topo[i]);

}

return 0;

}

```

通过上述两种方法的分析和代码实现,我们就可以利用信号量机制来表示前趋图中各进程或线程之间的执行顺序。

扫码领取最新备考资料


软考.png


软件设计师 资料下载
备考资料包大放送!涵盖报考指南、考情深度解析、知识点全面梳理、思维导图等,免费领取,助你备考无忧!
立即下载
软件设计师 历年真题
汇聚经典真题,展现考试脉络。精准覆盖考点,助您深入备考。细致解析,助您查漏补缺。
立即做题

软考资格查询系统

扫一扫,自助查询报考条件