需求来源于困难,在单片机上我们一般都是跑逻裸机,主要就是单线程加中断的方式写代码。
我个人很不喜欢用状态机的方式写代码,会很多的状态变量和全局参数。
但是我在一些场合遇到了不得不用状态机的时候,我写起来又不想又很多的全局变量,还希望代码模块化。到最后把我自己的代码眶的超难受。所以就萌生了伪多线程的需求。
之前就知道 setjmp longjmp两个函数可以实现函数间跳转,所以便尝试研究起来。
测试一、3个任务成环
#include "stdio.h"
#include <setjmp.h>
#include "stdbool.h"
#include "stdlib.h"
#include "stdint.h"
#include "string.h"
jmp_buf bf1;
jmp_buf bf2;
jmp_buf bf3;
bool flag1 = false;
bool flag2 = false;
bool flag3 = false;
void zfun3();
void zfun2();
void zfun1()
{
while (1)
{
printf("zfun1 执行\r\n");
if (setjmp(bf1) != 0)
{
printf("\tfun1 被调\r\n");
}
else
{
flag1 = true;
if (flag2)
{
longjmp(bf2, 1);
}
else
{
zfun2();
printf("\tfun1 退出zfun2\r\n");
}
}
}
}
void zfun2()
{
while (true)
{
printf("zfun2 执行\r\n");
if (setjmp(bf2) != 0)
{
printf("\tfun2 被调\r\n");
}
else
{
flag2 = true;
if (flag3)
{
longjmp(bf3, 1);
}
else
{
zfun3();
printf("\tzfun2 退出zfun3\r\n");
}
}
}
}
void zfun3()
{
while (true)
{
printf("zfun3 执行\r\n");
if (setjmp(bf3) != 0)
{
printf("\tfun3 被调\r\n");
}
else
{
flag3 = true;
if (flag1)
{
longjmp(bf1, 1);
}
else
{
zfun1();
printf("\tzfun2 退出zfun1\r\n");
}
}
}
}
int main()
{
printf_s("main 1\r\n");
//for (int i = 0; i < 10;i++)
zfun1();
printf_s("执行结束\r\n");
getchar();
}
测试二、试着开个口子
#include "stdio.h"
#include <setjmp.h>
#include "stdbool.h"
#include "stdlib.h"
#include "stdint.h"
#include "string.h"
jmp_buf bf1;
jmp_buf bf2;
jmp_buf bf3;
bool flag1 = false;
bool flag2 = false;
bool flag3 = false;
void zfun3();
void zfun2();
void zfun1()
{
//while (1)
{
printf("zfun1 执行\r\n");
if (setjmp(bf1) != 0)
{
printf("\tfun1 被调\r\n");
}
else
{
flag1 = true;
if (flag2)
{
longjmp(bf2, 1);
}
else
{
zfun2();
printf("\tfun1 退出zfun2\r\n");
}
}
}
}
void zfun2()
{
while (true)
{
printf("zfun2 执行\r\n");
if (setjmp(bf2) != 0)
{
printf("\tfun2 被调\r\n");
}
else
{
flag2 = true;
if (flag3)
{
longjmp(bf3, 1);
}
else
{
zfun3();
printf("\tzfun2 退出zfun3\r\n");
}
}
}
}
void zfun3()
{
while (true)
{
printf("zfun3 执行\r\n");
if (setjmp(bf3) != 0)
{
printf("\tfun3 被调\r\n");
}
else
{
flag3 = true;
if (flag1)
{
longjmp(bf1, 1);
}
else
{
zfun1();
printf("\tzfun2 退出zfun1\r\n");
}
}
}
}
int main()
{
printf_s("main 1\r\n");
//for (int i = 0; i < 10;i++)
while (true)
{
zfun1();
}
printf_s("执行结束\r\n");
getchar();
}
测试三、再添加一个任务
#include "stdio.h"
#include <setjmp.h>
#include "stdbool.h"
#include "stdlib.h"
#include "stdint.h"
#include "string.h"
jmp_buf bf1;
jmp_buf bf2;
jmp_buf bf3;
jmp_buf bf4;
bool flag1 = false;
bool flag2 = false;
bool flag3 = false;
bool flag4 = false;
void zfun3();
void zfun2();
void zfun4();
void zfun1()
{
//while (1)
{
printf("zfun1 执行\r\n");
if (setjmp(bf1) != 0)
{
printf("\tfun1 被调\r\n");
}
else
{
flag1 = true;
if (flag2)
{
longjmp(bf2, 1);
}
else
{
zfun2();
printf("\tfun1 退出zfun2\r\n");
}
}
}
}
void zfun2()
{
while (true)
{
printf("zfun2 执行\r\n");
if (setjmp(bf2) != 0)
{
printf("\tfun2 被调\r\n");
}
else
{
flag2 = true;
if (flag3)
{
longjmp(bf3, 1);
}
else
{
zfun3();
printf("\tzfun2 退出zfun3\r\n");
}
}
}
}
void zfun3()
{
while (true)
{
printf("zfun3 执行\r\n");
if (setjmp(bf3) != 0)
{
printf("\tfun3 被调\r\n");
}
else
{
flag3 = true;
if (flag4)
{
longjmp(bf4, 1);
}
else
{
zfun4();
printf("\tzfun3 退出zfun4\r\n");
}
}
}
}
void zfun4()
{
while (true)
{
printf("zfun4 执行\r\n");
if (setjmp(bf4) != 0)
{
printf("\tfun4 被调\r\n");
}
else
{
flag4 = true;
if (flag1)
{
longjmp(bf1, 1);
}
else
{
zfun1();
printf("\tzfun4 退出zfun1\r\n");
}
}
}
}
int main()
{
printf_s("main 1\r\n");
//for (int i = 0; i < 10;i++)
while (true)
{
zfun1();
}
printf_s("执行结束\r\n");
getchar();
}
测试四、5个线程调用正常
#include "stdio.h"
#include <setjmp.h>
#include "stdbool.h"
#include "stdlib.h"
#include "stdint.h"
#include "string.h"
jmp_buf bf1;
jmp_buf bf2;
jmp_buf bf3;
jmp_buf bf4;
jmp_buf bf5;
bool flag1 = false;
bool flag2 = false;
bool flag3 = false;
bool flag4 = false;
bool flag5 = false;
void zfun3();
void zfun2();
void zfun4();
void zfun5();
void zfun1()
{
//while (1)
{
printf("zfun1 执行\r\n");
if (setjmp(bf1) != 0)
{
}
else
{
flag1 = true;
if (flag2)
{
longjmp(bf2, 1);
}
else
{
zfun2();
printf("\tfun1 退出zfun2\r\n");
}
}
}
}
void zfun2()
{
static int i = 0;
while (true)
{
printf("zfun2 执行 %d \r\n",i++);
if (setjmp(bf2) != 0)
{
}
else
{
flag2 = true;
if (flag3)
{
longjmp(bf3, 1);
}
else
{
zfun3();
printf("\tzfun2 退出zfun3\r\n");
}
}
}
}
void zfun3()
{
static int i = 0;
while (true)
{
printf("zfun3 执行 %d \r\n", i++);
if (setjmp(bf3) != 0)
{
}
else
{
flag3 = true;
if (flag4)
{
longjmp(bf4, 1);
}
else
{
zfun4();
printf("\tzfun3 退出zfun4\r\n");
}
}
}
}
void zfun4()
{
static int i = 0;
while (true)
{
printf("zfun4 执行 %d \r\n", i++);
if (setjmp(bf4) != 0)
{
}
else
{
flag4 = true;
if (flag5)
{
longjmp(bf5, 1);
}
else
{
zfun5();
printf("\tzfun4 退出zfun5\r\n");
}
}
}
}
void zfun5()
{
static int i = 0;
while (true)
{
printf("zfun5 执行 %d \r\n", i++);
if (setjmp(bf5) != 0)
{
}
else
{
flag5 = true;
if (flag1)
{
longjmp(bf1, 1);
}
else
{
zfun1();
printf("\tzfun5 退出zfun1\r\n");
}
}
}
}
int main()
{
printf_s("main 1\r\n");
for (int i = 0; i < 10;i++)
{
zfun1();
}
printf_s("执行结束\r\n");
getchar();
}
测试五、封装
delay采用宏没问题,改成函数就会报错
#define delay() \
{ \
if (setjmp(context[ctx_id]->bf1) != 0) \
{ \
} \
else \
{ \
context[ctx_id]->flag1 = true; \
ctx_id++; \
if (ctx_id >= 4) \
ctx_id = 0; \
\
if (context[ctx_id]->flag1) \
{ \
longjmp(context[ctx_id]->bf1, 1); \
} \
else \
{ \
context[ctx_id]->zfun(); \
} \
} \
}
这样就正常了
#include "stdio.h"
#include <setjmp.h>
#include "stdbool.h"
#include "stdlib.h"
#include "stdint.h"
#include "string.h"
jmp_buf bf1;
jmp_buf bf2;
jmp_buf bf3;
jmp_buf bf4;
jmp_buf bf5;
bool flag1 = false;
bool flag2 = false;
bool flag3 = false;
bool flag4 = false;
bool flag5 = false;
void zfun1();
void zfun3();
void zfun2();
void zfun4();
void zfun5();
typedef struct
{
jmp_buf bf1;
bool flag1;
void(*zfun)();
}_context_t, *context_t;
context_t context[5];
int ctx_index = 0;
int ctx_id = 0;
void CreatTask(void(*fun)())
{
context_t ctx = (context_t)malloc(sizeof(_context_t));
memset(ctx, 0, sizeof(_context_t));
ctx->zfun = fun;
context[ctx_index++] = ctx;
}
void thread_init()
{
CreatTask(zfun1);
CreatTask(zfun2);
CreatTask(zfun3);
CreatTask(zfun4);
CreatTask(zfun5);
ctx_id = 0;
zfun1();//首次启动
}
#define delay()\
{\
if (setjmp(context[ctx_id]->bf1) != 0)\
{\
\
\
}\
else\
{\
context[ctx_id]->flag1 = true; \
ctx_id++; \
if (ctx_id >= 4)\
ctx_id = 0; \
\
if (context[ctx_id]->flag1)\
{\
longjmp(context[ctx_id]->bf1, 1); \
}\
else\
{\
context[ctx_id]->zfun(); \
}\
}\
}
void delay1()
{
if (setjmp(bf1) != 0)
{
}
else
{
flag1 = true;
if (flag2)
{
longjmp(bf2, 1);
}
else
{
zfun2();
printf("\tfun1 退出zfun2\r\n");
}
}
}
void delay2()
{
if (setjmp(bf2) != 0)
{
}
else
{
flag2 = true;
if (flag3)
{
longjmp(bf3, 1);
}
else
{
zfun3();
printf("\tzfun2 退出zfun3\r\n");
}
}
}
void zfun1()
{
//while (1)
{
printf("zfun1 执行\r\n");
delay();
}
}
void zfun2()
{
static int i = 0;
while (true)
{
printf("zfun2 执行 %d \r\n", i++);
delay();
printf("zfun2 执行 END %d \r\n", i++);
}
}
void zfun3()
{
static int i = 0;
while (true)
{
printf("zfun3 执行 %d \r\n", i++);
delay();
}
}
void zfun4()
{
static int i = 0;
while (true)
{
printf("zfun4 执行 %d \r\n", i++);
delay();
}
}
void zfun5()
{
static int i = 0;
while (true)
{
printf("zfun5 执行 %d \r\n", i++);
delay();
}
}
int main()
{
printf_s("main 1\r\n");
thread_init();
for (int i = 0; i < 10; i++)
{
zfun1();
}
printf_s("执行结束\r\n");
getchar();
}
结论
这次的验证说明 delay函数调用会破坏保存的堆栈结构