一、前言
状态机是非常常用的框架之一,本质就是通过记录状态值来执行对应动作,但是有个问题就是每个对应的状态值都有对应的动作,如果碰到需要等待信号量再触发的情况下需要特定处理,有没更好的方法处理这种情况呢,答案很多是有的。要解决这需求就要保证代码退出时和下次进入时的位置是不变的,怎么实现呢?
二、举例
这里还是采用状态机来实现,由于状态值没有发生改变,函数调用时触发的动作不变,这就保证了函数退出时和再次进入的“入口”相同。
#include <stdio.h> int function(void) { static int state; switch (state) { case 0: do { printf("state:%d\n", state); state = 1; return 0; case 1:; printf("state:%d\n", state); } while (0); } } int main() { function(); // 输出state:0 function(); // 输出state:1 function(); // 输出state:1 while (1) { } }
三、优化代码
在介绍优化前,先介绍一下C相关的宏:
int main() { printf("%d\n",__LINE__);//显示所在行号 printf("%s\n",__func__);//显示所在函数 printf("%s\n",__TIME__);//显示当前时间 printf("%s\n",__DATE__);//显示当前日期 printf("%s\n",__FILE__);//显示所处文件名,在源代码中插入当前源代码文件名 printf("%d\n",__STDC__);//编译器遵循ANSI C标准时该标识被赋值为1; return 0; }
简单优化一下:
#include <stdio.h> int state = 0; void function_init(void) { state = 0; } int function_handle(int condition) { switch (state) { case 0: do { state = __LINE__; case __LINE__: if (!condition) return 0; else return 1; } while (0); } } int main() { // 等待 int condition = 1; function_init(); if (!function_handle(condition)) { printf("pass\n"); } else { printf("obsolete\n"); } // 触发 condition = 0; function_init(); if (!function_handle(condition)) { printf("pass\n"); } else { printf("obsolete\n"); } // 等待 condition = 1; function_init(); if (!function_handle(condition)) { printf("pass\n"); } else { printf("obsolete\n"); } // 触发 condition = 0; function_init(); if (!function_handle(condition)) { printf("pass\n"); } else { printf("obsolete\n"); } while (1) { } }
四、封装
#include <stdio.h>
#define Begin() \
switch (state) \
{ \
case 0:
#define WAIT(condition) \
do \
{ \
state = __LINE__; \
case __LINE__: \
if (!condition) \
return 0; \
else \
return 1; \
} while (0)
#define End() }
int state = 0;
void function_init(void)
{
state = 0;
}
int function_handle(int condition)
{
Begin();
WAIT(condition);
End();
}
int main()
{
// 等待
int condition = 1;
function_init();
if (!function_handle(condition))
{
printf("pass\n");
}
else
{
printf("obsolete\n");
}
// 触发
condition = 0;
function_init();
if (!function_handle(condition))
{
printf("pass\n");
}
else
{
printf("obsolete\n");
}
// 等待
condition = 1;
function_init();
if (!function_handle(condition))
{
printf("pass\n");
}
else
{
printf("obsolete\n");
}
// 触发
condition = 0;
function_init();
if (!function_handle(condition))
{
printf("pass\n");
}
else
{
printf("obsolete\n");
}
while (1)
{
}
}
五、源码
最后就完成了一个简单的线程,纯C编写非常方便移植和改写!
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <stdint.h> #define PT_BEGIN() \ switch (pt->state) \ { \ case 0: #define PT_END() \ pt->state = 0; \ return 0; \ } #define PT_WAIT_UNTIL(condition) \ do \ { \ pt->state = __LINE__; \ case __LINE__: \ if (!(condition)) \ return 0; \ } while (0) typedef struct { uint8_t state; } pt_t; void pt_init(pt_t *pt) { pt->state = 0; } bool pt_run(pt_t *pt) { return pt->state != 0; } int thread_fun(pt_t *pt) { static uint32_t counter = 0; PT_BEGIN(); while (1) { printf("counter = %lu\n", counter++); PT_WAIT_UNTIL(counter % 10 == 0); } PT_END(); } int main() { pt_t pt_a; pt_t pt_b; pt_init(&pt_a); pt_init(&pt_b); while (true) { if (!pt_run(&pt_a)) { thread_fun(&pt_a); } if (!pt_run(&pt_b)) { thread_fun(&pt_b); } } return 0; }