[嘉楠 CanMV K230]测评 ⑤多线程
<div class='showpostmsg'><p> 在实际开发过程中,只靠一个while1是不够用的,需要有多线程。python中是带有多线程功能的(我平时FreeRTOS用的比较多,叫任务/task已经习惯了,后续可能顺手就打成任务/task,请见谅)</p><p> 可惜K230上不支持threading,只能支持_thread</p>
<div style="text-align: center;"></div>
<p> 在python官方文档关于_thread的内容如下:<a href="https://docs.python.org/3.5/library/_thread.html#module-thread" rel="noopener noreferrer" target="_blank">https://docs.python.org/3.5/library/_thread.html#module-thread</a></p>
<p> </p>
<p><strong><span style="font-size:24px;">一.创建线程并启动</span></strong></p>
<p> 接下来我们就来写一个demo,运行后创建2个task,第一个task为闪灯task,第二个为串口task。这两个task中执行的内容就是之前我们写过的</p>
<pre>
<code class="language-python">import _thread
import time
from machine import Pin
from machine import UART
from machine import FPIOA
fpioa = FPIOA()
#闪灯task
def task_blink():
#初始化52号引脚为输出模式,不拉高,驱动能力为默认的7
LED = Pin(52, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
while True:
#开灯
LED.value(1)
time.sleep(1)
#关灯
LED.value(0)
time.sleep(1)
#串口task
def task_uart():
#初始化串口2
fpioa.set_function(11,FPIOA.UART2_TXD)
fpioa.set_function(12,FPIOA.UART2_RXD)
my_uart = UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)
#发送数据测试
my_uart.write('UART2 send test\r\n')
#一直接收数据
while True:
#读取一行,并以一个换行符结束。
recv_data = my_uart.readline()
#如果有读到数据
if recv_data != b'':
#把收到数据通过日志串口打印出来
print(recv_data)
#把收到的数据原样从串口2发出去
my_uart.write(recv_data)
time.sleep(0.1)
#创建闪灯task和串口task
_thread.start_new_thread(task_blink, ())
_thread.start_new_thread(task_uart, ())
while True:
time.sleep(0.01) #防止CPU满跑
</code></pre>
<p>f7c8c71340c23ee5ae56892e0a92d4da<br />
</p>
<p><strong><span style="font-size:24px;">二.线程停止</span></strong></p>
<p><span style="font-size:16px;"><b>2.1 由别的task摧毁某个task</b></span></p>
<p> 在python的介绍中,_thread并没有制定摧毁某个task的接口,只有在task调用的函数退出运行,也就是要退出task中的while1</p>
<div style="text-align: center;"></div>
<p> 所以,我们可以使用一个flag,来决定while1是否可以运行,我这边偷懒,直接用一个全局变量,当然在多线程的环境下,各个task之间通讯用全局变量不合适,用队列比较好,不过我这边的使用场景比较简单,也不存在竞争,可以偷懒用一下</p>
<p> 我们来改造一下刚才的代码,当串口收到“STOP”后,把闪灯的task摧毁。收到“START”后,开始闪灯TASK</p>
<pre>
<code class="language-python">import _thread
import time
from machine import Pin
from machine import UART
from machine import FPIOA
fpioa = FPIOA()
# 全局变量作为标志位
task_blink_run_flag = False
#闪灯task
def task_blink():
global task_blink_run_flag
#初始化52号引脚为输出模式,不拉高,驱动能力为默认的7
LED = Pin(52, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
while task_blink_run_flag:
#开灯
LED.value(1)
time.sleep(1)
#关灯
LED.value(0)
time.sleep(1)
#串口task
def task_uart():
global task_blink_run_flag
#初始化串口2
fpioa.set_function(11,FPIOA.UART2_TXD)
fpioa.set_function(12,FPIOA.UART2_RXD)
my_uart = UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)
#发送数据测试
my_uart.write('UART2 send test\r\n')
#一直接收数据
while True:
#读取一行,并以一个换行符结束。
recv_data = my_uart.readline()
#如果有读到数据
if recv_data != b'':
#把收到数据通过日志串口打印出来
print(recv_data)
if recv_data == b'STOP\r\n':
print('recv stop')
# 避免task_blink被多次stop
if task_blink_run_flag == True:
task_blink_run_flag = False
else:
print('stop task_blink fail')
elif recv_data == b'START\r\n':
print('recv START')
# 避免task_blink被多次start
if task_blink_run_flag == False:
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
else:
print('start task_blink fail')
time.sleep(0.1)
#创建闪灯task和串口task
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
_thread.start_new_thread(task_uart, ())
while True:
time.sleep(0.01) #防止CPU满跑
</code></pre>
<p>98beafa1ea045a9f74da5438547a3984</p>
<p> </p>
<p><strong><span style="font-size:16px;">2.2 TASK自己摧毁自己</span></strong></p>
<p> 按照上述的思路,我们可以在task内部加一个变量,用于控制task中的while1,改造代码如下(为了看得清楚,其他部分我没动,新增了一个task)</p>
<pre>
<code class="language-python">import _thread
import time
from machine import Pin
from machine import UART
from machine import FPIOA
fpioa = FPIOA()
# 全局变量作为标志位
task_blink_run_flag = False
#闪灯task
def task_blink():
global task_blink_run_flag
#初始化52号引脚为输出模式,不拉高,驱动能力为默认的7
LED = Pin(52, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
while task_blink_run_flag:
#开灯
LED.value(1)
time.sleep(1)
#关灯
LED.value(0)
time.sleep(1)
#串口task
def task_uart():
global task_blink_run_flag
#初始化串口2
fpioa.set_function(11,FPIOA.UART2_TXD)
fpioa.set_function(12,FPIOA.UART2_RXD)
my_uart = UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)
#发送数据测试
my_uart.write('UART2 send test\r\n')
#一直接收数据
while True:
#读取一行,并以一个换行符结束。
recv_data = my_uart.readline()
#如果有读到数据
if recv_data != b'':
#把收到数据通过日志串口打印出来
print(recv_data)
if recv_data == b'STOP\r\n':
print('recv stop')
# 避免task_blink被多次stop
if task_blink_run_flag == True:
task_blink_run_flag = False
else:
print('stop task_blink fail')
elif recv_data == b'START\r\n':
print('recv START')
# 避免task_blink被多次start
if task_blink_run_flag == False:
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
else:
print('start task_blink fail')
time.sleep(0.1)
def task_destory_by_self():
flag = True
cnt = 0
while flag:
print('task_destory_by_self running')
cnt += 1
time.sleep(1)
if cnt >= 5:
flag = False
print('task_destory_by_self QUIT')
#创建闪灯task和串口task
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
_thread.start_new_thread(task_uart, ())
_thread.start_new_thread(task_destory_by_self, ())
while True:
time.sleep(0.01) #防止CPU满跑
</code></pre>
<p>可以看到,task_destory_by_self running打印 5次后,打印了task_destory_by_self QUIT,说明task是已经被摧毁了</p>
<p>091ca09e2e1082e2b877a20a2f77fc3c<br />
</p>
<p> 在python的文档中,还有一种方法,就是调用_thread.exit()函数,可以在task中直接退出,当执行这个函数后,TASK立刻被摧毁,这个函数后面的代码都不会被执行。代码如下</p>
<pre>
<code class="language-python">import _thread
import time
from machine import Pin
from machine import UART
from machine import FPIOA
fpioa = FPIOA()
# 全局变量作为标志位
task_blink_run_flag = False
#闪灯task
def task_blink():
global task_blink_run_flag
#初始化52号引脚为输出模式,不拉高,驱动能力为默认的7
LED = Pin(52, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
while task_blink_run_flag:
#开灯
LED.value(1)
time.sleep(1)
#关灯
LED.value(0)
time.sleep(1)
#串口task
def task_uart():
global task_blink_run_flag
#初始化串口2
fpioa.set_function(11,FPIOA.UART2_TXD)
fpioa.set_function(12,FPIOA.UART2_RXD)
my_uart = UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)
#发送数据测试
my_uart.write('UART2 send test\r\n')
#一直接收数据
while True:
#读取一行,并以一个换行符结束。
recv_data = my_uart.readline()
#如果有读到数据
if recv_data != b'':
#把收到数据通过日志串口打印出来
print(recv_data)
if recv_data == b'STOP\r\n':
print('recv stop')
# 避免task_blink被多次stop
if task_blink_run_flag == True:
task_blink_run_flag = False
else:
print('stop task_blink fail')
elif recv_data == b'START\r\n':
print('recv START')
# 避免task_blink被多次start
if task_blink_run_flag == False:
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
else:
print('start task_blink fail')
time.sleep(0.1)
def task_destory_by_self():
cnt = 0
while True:
print('task_destory_by_self running')
cnt += 1
time.sleep(1)
if cnt >= 5:
print('task_destory_by_self exit')
_thread.exit()
print('task_destory_by_self QUIT')
#创建闪灯task和串口task
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
_thread.start_new_thread(task_uart, ())
_thread.start_new_thread(task_destory_by_self, ())
while True:
time.sleep(0.01) #防止CPU满跑
</code></pre>
<p>9450d0deba6e2ef614d7a978afc4c8d5<br />
</p>
<p> </p>
<p> </p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>
页:
[1]