c - 从状态 Controller 检索状态的最佳方法是什么?

标签 c concurrency state-machine minix

对于一个学校项目,目标是创建一个由 3 个进程组成的实时系统,比如说“进程计算”和“进程执行”。在这两个进程之上,有一个状态持有者,我们将其称为这两个进程的“进程状态通信”。每当状态通信的状态发生变化时,两个进程都应该读取状态通信的状态,如果它是该进程中使用的状态,则必须在该进程内执行一个操作。检索状态通信进程状态的最佳方法是什么?因为此状态控制其他两个进程中发生的情况。 最后一件事,状态通信所做的就是根据其他两个进程相应地调整状态,因此它不会计算任何内容,这一切都发生在其他两个进程中。

对于计算和执行之间的通信,我们决定使用 FIFO 将计算中的数据发送到执行器。但是,这似乎不是状态通信的最佳解决方案,因为这应该是一个可由多个进程读取的 FIFO。但在 FIFO 中,一旦数据被一个进程读取,所有数据就会从管道中消失。

现在我的问题是,从“状态通信”中检索状态的最佳方法是什么,它可以由多个进程连续检索?

最佳答案

下面是用 C 语言实现状态机的一种方法。在下面的示例中,我使用 fork 来创建您提到的进程,并使用线程来模拟一些转换状态的输入。我已将这种模式用于以下情况:我有一个设备,该设备使用来自某些外部源的输入来实现状态机。

这可以通过多种方式完成,但是这种方法背后的核心思想是让工作线程(或进程)监视状态变量,让主线程(或进程)监视状态转换变量并相应地改变状态变量,然后是独立线程(或进程)根据接收到的外部数据改变状态转换变量。

请记住,主线程有必要“重置”状态转换变量,以便它不会立即转换出新状态。我通过创建 NO OP 过渡状态来做到这一点。由于 main 和ExternalSource 都写入状态转换变量,因此我使用互斥体进行保护。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <string.h>

pthread_mutex_t mutex; 


typedef enum _State{
    EXECUTE,    
    IDLE,    
    CALCULATE
} State;


typedef enum _StateTransition{
    TRANS_EXECUTE,    
    TRANS_IDLE,    
    TRANS_CALCULATE,
    TRANS_NOOP
} StateTransition;


void Calculate(State *state_p){
    int flag = 0; // Only calculate once per state transition
    while (1){
        if ((*state_p == CALCULATE) && flag){
            puts("Calculated");
            flag = 0;
        } else if (*state_p != CALCULATE){
            flag = 1;
        }
    }
}


void Execute(State *state_p){
    int flag = 0; // Only execute once per state transition
    while (1){
        if ((*state_p == EXECUTE) && flag){
            puts("executed");
            flag = 0;
        } else if (*state_p != EXECUTE){
            flag = 1;
        }
    }
}


void * ExternalSource(void * param){
    StateTransition * transition_p = (StateTransition*) param;

    // Emulate External input
    while(1){
        sleep(2);
        puts("Transiton to idle");
        pthread_mutex_lock(&mutex);
        *transition_p = TRANS_IDLE;
        pthread_mutex_unlock(&mutex);

        sleep(2);
        puts("Transition to calculate");
        pthread_mutex_lock(&mutex);
        *transition_p = TRANS_CALCULATE;
        pthread_mutex_unlock(&mutex);

        sleep(2);
        puts("Transition to execute");
        pthread_mutex_lock(&mutex);
        *transition_p = TRANS_EXECUTE;
        pthread_mutex_unlock(&mutex);    
    }
}



int main()
{
    pthread_t externalThread;
    int rv;
    pid_t pidExecute;
    pid_t pidCalculate;
    volatile StateTransition transition;
    State * state;

    // Setup Initial Values
    transition = TRANS_NOOP;
    state = mmap(NULL, sizeof(State), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
    *state = IDLE;

    // Create Processes for Calculate and Execute
    pidExecute = fork();
    if (pidExecute == 0){
        Execute(state);
    } else{
        pidCalculate = fork();
        if (pidCalculate == 0){
            Calculate(state);
        }
    }

    // Create Thread for Input Emulation
    rv = pthread_create(&externalThread, NULL, ExternalSource, (void*)&transition);
    if (rv){
        perror("ERROR Unable to create thread");
        return -1;
    }


    while(1){ //Implement State Machine

        switch (*state){

        case IDLE:
            if (transition == TRANS_CALCULATE){
                // Do some transition stuff    

                *state = CALCULATE; // Update new state
                pthread_mutex_lock(&mutex);
                transition = TRANS_NOOP; // Reset transition
                pthread_mutex_unlock(&mutex);

            }
            break;

        case CALCULATE:
            if (transition == TRANS_EXECUTE){
                // Do some transition stuff

                *state = EXECUTE; // Update new state        
                pthread_mutex_lock(&mutex);    
                transition = TRANS_NOOP; // Reset transition
                pthread_mutex_unlock(&mutex);
            }
            break;

        case EXECUTE:
            if (transition == TRANS_IDLE){
                // Do some transition stuff

                *state = IDLE; // Update new state            
                pthread_mutex_lock(&mutex);        
                transition = TRANS_NOOP; // Reset transition            
                pthread_mutex_unlock(&mutex);
            }
            break;

        default:
            break;
        }
    }

    return 0;
}

此代码确实可以编译,但它与平台无关。这实际上只是为了演示这个想法。如果您打算使用此代码作为起点,请确保了解每一行中发生的情况,否则从长远来看,它最终会花费您更多的时间。

关于c - 从状态 Controller 检索状态的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47657524/

相关文章:

c++ - 如何调试一个不那么熟悉的庞大代码库?

c++ - 如何停止正在阻塞的 win32 线程?

algorithm - 如何合并两个有限状态自动机?

c# - 使用 "yield"关键字实现状态机

c - 如何编写与内核模块通信的shell脚本

c - 编译 C 代码时,如何指定要从 .so 库导出的函数?

c - 显示一个数组,用指针排序,然后在 C 中再次显示原始数组

concurrency - Golang 上传整个目录并发返回到许多打开的文件

java - final 字段如何防止其他线程看到部分构造的对象?

python - 在Python中的圆圈内插入文本