对于学校项目,目标是建立一个存在于3个过程中的实时系统,让我们说“过程计算”和“过程执行”。在这两个进程之上,有一个状态持有者,我们称之为“进程状态通信”,即2个进程。每当状态通信状态发生变化时,2个进程应该读取状态通信的状态,如果它是在该进程中使用的状态,则必须在该进程内执行动作。检索状态通信过程状态的最佳方法是什么?由于此状态控制其他2个进程中发生的情况。 最后一点,所有的状态通信都是相应地调整状态到另外两个进程,所以它不会计算任何东西,这一切都发生在其他2个进程中。
对于计算和执行之间的通信,我们决定使用FIFO将数据从计算发送到执行器。但是,这似乎不是状态通信的最佳解决方案,因为这应该是一个可由多个进程读取的FIFO。但是在FIFO中,一旦一个进程读取数据,所有数据都会从管道中消失。
现在我的问题是,从“statecommunication”中检索状态的最佳方法是什么,可以通过多个进程连续检索?
答案 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;
}
此代码可以编译,但不平台无关。这只是为了证明这个想法。如果您打算将此代码用作起始位置,请确保了解每行中发生的情况,否则最终会花费更多时间。