对于一个学校项目,目标是创建一个由 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/