彻底搞清楚多线程编程

2023-12-16 09:30

本文主要是介绍彻底搞清楚多线程编程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

很多时候在主线程中运行的程序需要一个while true,但是这样会导致程序整体上非常庞大,引入多线程来减少主线程的内容,同时也能顺利的实现功能,还有一个问题在于多线程还可以一定程度上减少全局变量(但是也是需要反复运行反复获得return,没有全局变量用着舒服)

多线程编程的作用就是上面所描述的哪些,那么如何编写一个可控的msg呢?

Emergency_brake_threading = threading.Thread(target=emergency_brake_decision)    

其中emergency_brake_decision为

def emergency_brake_decision1():while not rospy.is_shutdown():print("1")

一个线程不是说反复会执行自己的函数,而是执行本函数。如果当前函数是一个循环,那就是会一个执行循环中的内容的,所以说,不要想当然就认为线程就是一个无限执行一个函数,而是单独在启动线程后可以同时执行启动的线程的函数,其运行情况由其本身决定
完整来说:

import threading
import timedef thread_prc1(a):print(a)def thread_prc2(b,a):print(b)
a=0
b=1while a<100:a+=1b+=2Threading_prc1 = threading.Thread(target=thread_prc1,args=(a,))Threading_prc2 = threading.Thread(target=thread_prc2,args=(b,a))#启动Threading_prc1.start()Threading_prc2.start()#等待结束Threading_prc1.join()Threading_prc2.join()

线程默认是一直执行的,直到线程函数结束或者线程被显式地停止或中断。Threading_prc1线程会执行 thread_prc1函数,并将a作为参数传递给函数。这是一个最简单的线程。循环可以写在线程里面也可以在外面,如果希望它是反复执行的话。

然后就是如果线程有返回值的问题了,线程有返回值其实就是说明线程已经执行完一次了,如果不希望他影响主频率,那么它的执行速度必须也是很快的。而且循环要写在外面:

import threading
import time
b=1class MyThread(threading.Thread):def __init__(self, target, args=()):super().__init__(target=target, args=args)self.result = Nonedef run(self):self.result = self._target(*self._args)def thread_prc1(a):k = 1k+=1print(a)return kdef thread_prc2():global bprint(b)def main():global ba=0while a<100:a+=1b+=2Threading_prc1 = MyThread(target=thread_prc1,args=(a,))Threading_prc2 = threading.Thread(target=thread_prc2)#启动Threading_prc1.start()Threading_prc2.start()#等待结束Threading_prc1.join()##每次结束后都有返回值:result = Threading_prc1.resultprint("k",result)print("b",b)Threading_prc2.join()if __name__ == "__main__":main()

注意,threading.Thread是没有办法拿到返回值的,所以其实还是需要全局变量,虽然可以用自己定义的MyThread拿到返回值,不过基本也不这么干。
最最后,是一个用时间变化的线程去改变车辆速度:在这里插入代码片

### !/usr/bin/python3
# -*- coding: utf-8 -*-##减速测试 base_wirecontrol
import time
import matplotlib.pyplot as pltimport can
import cantools
import rospy
import time
import std_msgs.msg
from car_interfaces.msg import CarOriInterface,PathSpeedCtrlInterface
import os
import signal
import json
import threadingbrake_flag = False
Brake = False
Brake_end = Falseflag_steer = 0
q_num = 0
quit_mod = False
is_exit = False
start_flag = False
target_vel = 0#17  #车辆速度设置
target_steer_vel = 50  # 车辆方向盘转角速度
num = 0
bus_vel = 0
veh_cte = 0vel_plan = 0flag_end = 0 #终点停车只执行一次flag_spd_start = 1#状态转换
flag_spd_start_brake = 1#状态转换y = 0import os
import sys
# 获取当前脚本文件的所在目录
script_directory = os.path.dirname(os.path.abspath(__file__))
# 图片文件相对于脚本文件的路径
image_relative_path = 'lib'
# 构建图片文件的完整路径
icon_path = os.path.join(script_directory, image_relative_path)
# absolute_path = os.path.abspath(icon_path)# print(absolute_path)
sys.path.append(icon_path)
from base_function import *
class MyThread(threading.Thread):def __init__(self, target, args=()):super().__init__(target=target, args=args)self.result = Nonedef run(self):self.result = self._target(*self._args)def signal_handler(signal, frame):global is_exitis_exit = Truemessages_1 = [      # 发送给整车VCU的报文类型{'message_id': 0x0C01D0A5,    # 车辆方向盘转向信息报文'message_name': 'steering_control','signals': {'target_steering_angle': 0,     # 车辆方向盘角度,两字节表示'target_steering_mod': 5,       # 车辆转向控制模式,4 bit表示,置1为转角控制模式,若手动后,则置5后再置1'DCU_valid': 1,                 # VCU状态,1为正常,0为不正常,1 bit表示'steering_control_valid': 1,    # 车辆转角状态,1为正常,0不正常,1 bit表示'target_steering_torque': 0,    # 转向叠加扭矩信号,目前可以先取128中间值,一字节表示'target_steering_velocity': target_steer_vel,  # 方向盘目标角速度,5-54对应50 ~ 540°/s,分辨率为10,一字节表示'steering_msg_life': 0,         # 该消息发送的生命周期}},{'message_id': 0x0C02D0A5,   # 车辆qudong信息报文'message_name': 'drive_control','signals': {'target_velocity': target_vel,'target_acceleration': 0,'target_direction': 1,'fault_code': 0,'drive_msg_life': 0,}},{'message_id': 0x0C03D0A5,  # 车辆zhidong# 信息报文'message_name': 'barke_control','signals': {'target_deceleration': 0,'XBR2_EBI_Mode': 0,'XBR2_Priority': 0,'XBR2_Ctrl_Mode': 0,'XBR2_message_counter': 0,'XBR2_checksum': 0,}},{'message_id': 0x0C04D0A5,  # 车辆整车速度信息报文'message_name': 'body_control','signals': {'mode_disp': 0,'body_state': 1,'turning_lighting_control': 0,'high_low_beam_control': 2,'hazard_lights_control': 0,'backup_light_control': 0,'width_lamp_control': 0,'wiper_wash_switch' : 0,'front_door_control': 0,'middle_door_control': 0,'horn_control' : 0,}},{'message_id': 0x0C08D0A5,  # 车辆整车速度信息报文'message_name': 'parking_control','signals': {'longterm_park_req': 0,'temp_park_req': 0,'park_control_mode': 0,'park_work_mode': 0,'park_air_pressure': 0,'temp_park_pressure': 0,'park_msg_checksum': 10,}},
]def msg_send_to_vcu(messages_1,dbc,bus):#置发送了messageglobal countglobal brake_flagglobal bus_vel# 以下向车辆VCU发送了方向盘转角规划信息global flag_steerglobal Brakeglobal q_numglobal quit_modglobal steer_modglobal count1msg_send = dbc.get_message_by_name(messages_1[0]['message_name'])messages_ = list(msg_send.encode(messages_1[0]['signals']))messages_send = can.Message(arbitration_id=msg_send.frame_id, data=messages_, is_extended_id=True)msg_send11 = dbc.get_message_by_name(messages_1[1]['message_name'])messages_11 = list(msg_send11.encode(messages_1[1]['signals']))messages_send11 = can.Message(arbitration_id=msg_send11.frame_id, data=messages_11, is_extended_id=True)msg_send33 = dbc.get_message_by_name(messages_1[2]['message_name'])messages_33 = list(msg_send33.encode(messages_1[2]['signals']))messages_send33 = can.Message(arbitration_id=msg_send33.frame_id, data=messages_33, is_extended_id=True)msg_send44 = dbc.get_message_by_name(messages_1[3]['message_name'])messages_44 = list(msg_send44.encode(messages_1[3]['signals']))messages_send44 = can.Message(arbitration_id=msg_send44.frame_id, data=messages_44, is_extended_id=True)msg_send88 = dbc.get_message_by_name(messages_1[4]['message_name'])messages_88 = list(msg_send88.encode(messages_1[4]['signals']))messages_send88 = can.Message(arbitration_id=msg_send88.frame_id, data=messages_88, is_extended_id=True)bus.send(messages_send)bus.send(messages_send11)bus.send(messages_send33)bus.send(messages_send44)bus.send(messages_send88)def msg_recv_from_vcu(dbc,bus):     # 从整车VCU中得到车辆目前实际相关信息,并放入到信息meg_car_ori中global bus_velglobal steer_modglobal quit_modglobal messages_1global countglobal count1global brake_flagglobal q_numglobal target_velglobal vel_planmessages_recv = bus.recv()drive_life = messages_1[1]['signals']['drive_msg_life']drive_life += 1if drive_life > 255:drive_life -= 256messages_1[1]['signals']['drive_msg_life'] = drive_lifepark_life = messages_1[4]['signals']['park_msg_checksum']park_life += 1if park_life > 255:park_life -= 256messages_1[4]['signals']['park_msg_checksum'] = park_lifeif start_flag:messages_1[3]['signals']['mode_disp'] = 1else:messages_1[3]['signals']['mode_disp'] = 0messages_1[1]['signals']['target_velocity'] = 0if messages_1[0]['signals']['target_steering_mod'] == 5:messages_1[1]['signals']['target_velocity'] = 0q_num += 1if q_num >= 20:messages_1[0]['signals']['target_steering_mod'] = 1# print(messages_1[0]['signals']['target_steering_mod'],"k"*12)#当前速度if messages_recv.arbitration_id == 0x0C06A5D0:decoded_messages = dbc.decode_message(messages_recv.arbitration_id, messages_recv.data)bus_vel = decoded_messages['act_vehicle_velocity']    def can_stop_thread(dbc, bus):global messages_2messages_2 = [      # 发送给整车VCU的报文类型{'message_id': 0x0C01D0A5,    # 车辆方向盘转向信息报文'message_name': 'steering_control','signals': {'target_steering_angle': 0,     # 车辆方向盘角度,两字节表示'target_steering_mod': 5,       # 车辆转向控制模式,4 bit表示,置1为转角控制模式,若手动后,则置5后再置1'DCU_valid': 1,                 # VCU状态,1为正常,0为不正常,1 bit表示'steering_control_valid': 1,    # 车辆转角状态,1为正常,0不正常,1 bit表示'target_steering_torque': 0,    # 转向叠加扭矩信号,目前可以先取128中间值,一字节表示'target_steering_velocity': 300,  # 方向盘目标角速度,5-54对应50 ~ 540°/s,分辨率为10,一字节表示'steering_msg_life': 0,         # 该消息发送的生命周期}},{'message_id': 0x0C02D0A5,   # 车辆qudong信息报文'message_name': 'drive_control','signals': {'target_velocity': 0,'target_acceleration': 0,'target_direction': 1,'fault_code': 0,'drive_msg_life': 0,}},{'message_id': 0x0C03D0A5,  # 车辆zhidong# 信息报文'message_name': 'barke_control','signals': {'target_deceleration': 0,'XBR2_EBI_Mode': 0,'XBR2_Priority': 0,'XBR2_Ctrl_Mode': 0,'XBR2_message_counter': 0,'XBR2_checksum': 0,}},{'message_id': 0x0C04D0A5,  # 车辆整车速度信息报文'message_name': 'body_control','signals': {'mode_disp': 0,'body_state': 1,'turning_lighting_control': 0,'high_low_beam_control': 0,'hazard_lights_control': 0,'backup_light_control': 0,'width_lamp_control': 0,'wiper_wash_switch' : 0,'front_door_control': 0,'middle_door_control': 0,'horn_control' : 0,}},{'message_id': 0x0C08D0A5,  # 车辆整车速度信息报文'message_name': 'parking_control','signals': {'longterm_park_req': 0,'temp_park_req': 0,'park_control_mode': 0,'park_work_mode': 0,'park_air_pressure': 0,'temp_park_pressure': 0,'park_msg_checksum': 10,}},]msg_send_to_vcu(messages_2, dbc, bus)bus.shutdown()print('\nall threads were ended by Ctrl-C')def speed_change_brake(interval,total_time):global y #速度start_time = time.time()time_list = []y_list = []k = 0# 循环计算并记录时间和 y 的值while True:# 计算经过的时间elapsed_time = time.time() - start_time# 检查是否超过总运行时间,如果超过则跳出循环if elapsed_time <= total_time:  ##5s加速到10y = 10t = elapsed_time  # 时间变量y_list.append(y)time_list.append(t)# print(elapsed_time)elif y >= -0.1:if k==0:k = 1start_time_ = time.time()time_ = time.time() - start_time_# 计算 y 的值t = time_  # 时间变量if y <= 0:y = 0else:y = -1 * t + 10if y <0:y=0# print(time_)# 记录时间和 y 的值time_list.append(t)y_list.append(y)if y <= 0 and time_ > 15:breakprGreen(time_)result = y_list# 等待一段时间,控制循环速率time.sleep(interval)prRed(y)return resultdef prRed(skk): print("\033[91m {}\033[00m".format(skk))def prGreen(skk): print("\033[92m {}\033[00m".format(skk))def prYellow(skk): print("\033[93m {}\033[00m".format(skk))def prBlue(skk): print("\033[94m {}\033[00m".format(skk))
def prPurple(skk): print("\033[95m {}\033[00m".format(skk))
def prCyan(skk): print("\033[96m {}\033[00m".format(skk))def prOrange(skk): print("\033[33m {}\033[00m".format(skk))def prPink(skk): print("\033[95m {}\033[00m".format(skk))def main():global is_exitglobal yflag_wire = 0signal.signal(signal.SIGINT, signal_handler)script_directory = os.path.dirname(os.path.abspath(__file__))relative_path = "../config/car_vcu2.dbc"gps_dbc_file = os.path.join(script_directory, relative_path)dbc = cantools.db.load_file(gps_dbc_file)bus = can.interface.Bus(channel='can0', bustype='socketcan')rospy.init_node('pub_vcu1', anonymous=False)print("success")interval = 0.001  # 时间间隔,单位为秒total_time = 5  # 总运行时间,单位为秒Speed_value_threading = MyThread(target=speed_change_brake, args=(interval, total_time))    Speed_value_threading.start()Speed_value_threading.join()result = Speed_value_threading.result# time.sleep(0.01)x_values = list(range(len(result)))  plt.scatter(x_values, result)plt.xlabel('Time')plt.ylabel('y')plt.title('speed 曲线')plt.show()while not is_exit :if flag_wire == 0 :  # 0-wirecontrol发布 1-不发布messages_1[1]['signals']['target_velocity'] = ymsg_recv_from_vcu(dbc, bus)msg_send_to_vcu(messages_1, dbc, bus)time.sleep(0.01)Can_shutdown_threading = threading.Thread(target=can_stop_thread,args=())Can_shutdown_threading.start()Can_shutdown_threading.join()if __name__ == '__main__':main()

到目前为止现在是对线程的写法和运行机理理解最深的时候。

这篇关于彻底搞清楚多线程编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/499985

相关文章

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)

多线程解析报表

假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。 Way1 join import java.time.LocalTime;public class Main {public static void main(String[] args) thro

Java并发编程之——BlockingQueue(队列)

一、什么是BlockingQueue BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种: 1. 当队列满了的时候进行入队列操作2. 当队列空了的时候进行出队列操作123 因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空

Java 多线程概述

多线程技术概述   1.线程与进程 进程:内存中运行的应用程序,每个进程都拥有一个独立的内存空间。线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换、并发执行,一个进程最少有一个线程,线程实际数是在进程基础之上的进一步划分,一个进程启动之后,进程之中的若干执行路径又可以划分成若干个线程 2.线程的调度 分时调度:所有线程轮流使用CPU的使用权,平均分配时间抢占式调度

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):