从状态控制器检索状态的最佳方法是什么?

时间:2017-12-05 15:46:45

标签: c concurrency state-machine minix

对于学校项目,目标是建立一个存在于3个过程中的实时系统,让我们说“过程计算”和“过程执行”。在这两个进程之上,有一个状态持有者,我们称之为“进程状态通信”,即2个进程。每当状态通信状态发生变化时,2个进程应该读取状态通信的状态,如果它是在该进程中使用的状态,则必须在该进程内执行动作。检索状态通信过程状态的最佳方法是什么?由于此状态控制其他2个进程中发生的情况。 最后一点,所有的状态通信都是相应地调整状态到另外两个进程,所以它不会计算任何东西,这一切都发生在其他2个进程中。

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

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

1 个答案:

答案 0 :(得分:1)

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

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

请记住,主线程必须“重置”状态转换变量,以便它不会立即转换出新状态。我通过创建一个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;
}

此代码可以编译,但平台无关。这只是为了证明这个想法。如果您打算将此代码用作起始位置,请确保了解每行中发生的情况,否则最终会花费更多时间。