在使用vrep的thread scirpt的时候我竟然会对这么简单的一个问题产生疑惑,但是为了要多学习,多进步,还是把这个问题记录一下:

一个文件里有许多的函数。一个函数执行完了,会执行到另外一个函数。在执行某个函数的时候,中间也会跑出去执行别的函数,这怎么用线程的概念来解释它?  这个问题可以用时间片轮转来解释:

在单核cpu中程序是片段执行,程序员就必须理解,在自己的程序运行时不是独一无二的,我们看似很顺畅的工作,其实是由一个个的执行片段构成的,我们眼中相邻的两条语句甚至同一个语句中两个不同的运算符之间,都有可能插入其他线程或进程的动作。具体查看时间片轮转调度

在vrep thread scirpt中,每隔2ms就会自动切换到另外一个线程,2ms之后在切换回来。sim.setThreadAutomaticSwitch()、sim.switchthread()等函数就是用来控制这个过程的。sim.setThreadAutomaticSwitch()能够禁止自动切换。sim.switchthread()指明在哪个时刻从一个线程切换到另外一个线程。我想这可能和vrep的thread scirpt管理机制有关,毕竟一个scene里可以有好几个的thread scirpt,每一个thread scirpt都是需要执行的。

接下来稍微具体的介绍一下这个过程。

1.线程和协程的概念

   (1)线程

  首先复习一下多线程。我们都知道线程——Thread。每一个线程都代表一个执行序列。当我们在程序中创建多线程的时候,看起来,同一时刻多个线程是同时执行的,不过实质上多个线程是并发的,因为只有一个CPU,所以实质上同一个时刻只有一个线程在执行。在一个时间片内执行哪个线程是不确定的,我们可以控制线程的优先级,不过真正的线程调度由CPU的调度决定。

   (2)协程

  那什么是协程呢?协程跟线程都代表一个执行序列。不同的是,协程把线程中不确定的地方尽可能的去掉,执行序列间的切换不再由CPU隐藏的进行,而是由程序显式的进行。

  所以,使用协程实现并发,需要多个协程彼此协作。

Lua的多线程并不是真的多线程,而是协程——Lua的线程和状态、Lua中的协同程序

协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈、局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。从概念上讲,线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。就是说,一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停。[1]

Lua不支持真正的多线程,而是一种协作式的多线程,彼此之间协作完成,并不是抢占完成任务,由于这种协作式的线程,因此可以避免由不可预知的线程切换所带来的问题;另一方面,Lua的多个状态之间不共享内存,这样便为Lua中的并发操作提供了良好的基础。

coroutine运行一系列的协作多线程。每个coroutine相当于一个thread。通过yield-resume实现在不同thread之间切换控制权。但是,跟常规的多线程不同,coroutine是非抢占式的。一个coroutine在运行的时候,不可能被其他的coroutine从外部将其挂起,只有由其本身显式地调用yield才会挂起,并交出控制权。对一些程序来说,这没有任何问题,相反,因为非抢占式的缘故,程序变得更加简单。我们不需要担心同步问题的bug,因为在threads之间的同步都是显式的。我们只需要保证在对的时刻调用yield就可以了

2.1Non-threaded child scripts 单线程脚本/非线程脚本

单线程的程序执行时,是按照顺序执行的。The script is non-threaded. In that case, it behaves as a function that is called in each simulation step. This also means, it is inherently synchronized with the main simulation loop.

2.2 Threaded child scripts 多线程子脚本

每一个脚本都在一个thread里启动。

The script is threaded. In that case, you can precisely time your code to be synchronized with the main simulation loop with following few instructions:

  • sim.SetThreadAutomaticSwitch()
  • sim.SwitchThread()

You can also specify at which time the threaded script resumes, using sim.SetThreadResumeLocation() .All that functionality is allowed because threaded scripts in V-REP behave more like coroutines

simSetThreadResumeLocation / sim.setThreadResumeLocation 可以决定位置和脚本的执行顺序

simSetThreadSwitchTiming / sim.setThreadSwitchTiming 指定当前线程在切换到另外一个线程的之前,此线程执行多长时间

a threaded child script is running more like a coroutine than a thraditional thread:

By default, when a threaded child script is launched, it will execute about 2ms. Then V-REP will interrupt or pause it, and only resume it in next simulation step (i.e. when the simulation time has become t=t+dt). It will resume for about 2ms, and be interrupted again. And resume again in next simulation step, and so on, and so forth.

代码片段1:没有线程切换函数,while loop会浪费宝贵的计算资源。需要再while loop里执行完一个2ms

function sysCall_threadmain()
-- Put some initialization code here:
sensorHandleFront=sim.getObjectHandle("DoorSensorFront")
sensorHandleBack=sim.getObjectHandle("DoorSensorBack")
motorHandle=sim.getObjectHandle("DoorMotor")
-- Here we execute the regular thread code:
while sim.getSimulationState()~=sim.simulation_advancing_abouttostop do
resF=sim.readProximitySensor(sensorHandleFront)
resB=sim.readProximitySensor(sensorHandleBack)
if ((resF>0)or(resB>0)) then
sim.setJointTargetVelocity(motorHandle,-0.2)
else
sim.setJointTargetVelocity(motorHandle,0.2)
end
-- this loop wastes precious computation time since we should only read new
-- values when the simulation time has changed (i.e. in next simulation step).
end
end
function sysCall_cleanup()
-- Put some clean-up code here:
end

默认情况下,vrep每隔两毫秒就会自动从一个线程切换到另外一个线程。然后就会在下一个simulation pass恢复执行。

sim.switchthread() 能够缩短时间,提高效率(把2ms缩短,可以和代码1进行对比 )

V-REP uses threads to mimic(模拟) the behavior of coroutines, instead of using them traditionally, which allows for a great deal of flexibility and control: by default a threaded child script will execute for about 1-2 milliseconds before automatically switching to another thread. This default behavior can be changed with the sim.setThreadSwitchTiming or sim.setThreadAutomaticSwitch. Once the current thread was switched, it will resume execution at next simulation pass (i.e. at a time currentTime+simulationTimeStep). The thread switching is automatic (occurs after the specified time), but the sim.switchThread command allows to shorten that time when needed. Using above three commands, an excellent synchronization with the main simulation loop can be achieved. Following code (handling the automatic sliding doors from above's example) shows child script synchronization with the main simulation loop

代码片段2:使用线程切换函数sim.setThreadAutomaticSwitch(false)、sim.switchthread()
对代码片段1进行改变,来得到更好的效果:不会浪费宝贵的计算资源而且能够和仿真同步运行

function sysCall_threadmain()-- Put some initialization code here:sim.setThreadAutomaticSwitch(false) -- disable automatic thread switchessensorHandleFront=sim.getObjectHandle("DoorSensorFront")sensorHandleBack=sim.getObjectHandle("DoorSensorBack")motorHandle=sim.getObjectHandle("DoorMotor")-- Here we execute the regular thread code:while sim.getSimulationState()~=sim.simulation_advancing_abouttostop doresF=sim.readProximitySensor(sensorHandleFront)resB=sim.readProximitySensor(sensorHandleBack)if ((resF>0)or(resB>0)) thensim.setJointTargetVelocity(motorHandle,-0.2)elsesim.setJointTargetVelocity(motorHandle,0.2)endsim.switchThread() -- Explicitely switch to another thread now!-- from now on, above loop is executed once every time the main script is about to execute.-- this way you do not waste precious computation time and run synchronously.
    -- 以上的循环在main scirpt里只会执行一次。这样做不会浪费宝贵的计算资源而且能够和仿真同步运行end
end

3.与thread scirpt相关的常用函数

simSetThreadAutomaticSwitch / sim.setThreadAutomaticSwitch

Description Allows to temporarily forbid thread switches. If the current script doesn't run in a thread (i.e. if it runs in the application main thread), this function has no effect. By default, V-REP doesn't use "regular" threads, but something similar to hybrid threads (which behave like coroutines, but can also behave like regular threads). This allows much more flexibility and execution control of the threads. For complete control over the switching moment, see also sim.getThreadAutomaticSwitch, sim.setThreadSwitchTiming, sim.switchThread, sim.setThreadIsFree and sim.setThreadResumeLocation.
C synopsis      -
C parameters -
C return value -
Lua synopsis number result=sim.setThreadAutomaticSwitch(Boolean switchIsAutomatic)
Lua parameters
switchIsAutomatic: if true, the thread will be able to automatically switch to another thread, otherwise the switching is temporarily disabled.
Lua return values
result: 1 if the command was successful, 0 if it didn't have an effect (e.g. because the function was called from the main or application thread), or -1 in case of an error.

simSwitchThread / sim.switchThread 在某个时刻将当前线程切换到另外一个线程

Description Allows specifying the exact moment at which the current thread should switch to another thread. If the current script doesn't run in a thread (i.e. if it runs in the application main thread), this function has no effect. By default, V-REP doesn't use "regular" threads, but something similar to hybrid threads (which behave like coroutines, but can also behave like regular threads). This allows much more flexibility and execution control of the threads: each thread (except for the main or application thread) has a switch timing associated, which specifies how long the thread will run before switching to other threads. By default this value is 2 millisecond, but can be modified with sim.setThreadSwitchTiming. That timing can be shortened with sim.switchThread. Use with care when calling this function from a plugin. See also the sim.setThreadAutomaticSwitch, sim.setThreadResumeLocation and sim.setThreadIsFree functions.
C synopsis simInt simSwitchThread()
C parameters None
C return value 1 if the thread was switched (the current thread gave control to other threads until the next calculation pass), 0 if it was not switched (e.g. because the function was called from the main or application thread, or from a thread started by the user), or -1 in case of an error.
Lua synopsis number result=sim.switchThread()
Lua parameters None
Lua return values result: 1 if the thread was switched (the current thread gave control to other threads until the next calculation pass), 0 if it was not switched (e.g. because the function was called from the main or application thread), or -1 in case of an erro

simSetThreadSwitchTiming / sim.setThreadSwitchTiming指定当前线程在切换到另外一个线程的之前,此线程执行多长时间

Description Allows specifying a switching time for the thread in which the current script runs. If the current script doesn't run in a thread (i.e. if it runs in the application main thread), this function has no effect. By default, V-REP doesn't use "regular" threads, but something similar to hybrid threads (which behave like coroutines, but can also behave like regular threads). This allows much more flexibility and execution control of the threads: each thread (except for the main or application thread) has a switch timing associated, which specifies how long the thread will run before switching to other threads (the execution duration per calculation pass). By default this value is 2 millisecond, but this function allows changing that value (on a thread-basis). Acceptable values are between 0 and 200. For complete control over the switching moment, see also sim.setThreadAutomaticSwitch, sim.switchThread, sim.setThreadIsFree and sim.setThreadResumeLocation.
C synopsis -
C parameters -
C return value -
Lua synopsis number result=sim.setThreadSwitchTiming(number deltaTimeInMilliseconds)
Lua parameters
deltaTimeInMilliseconds: desired non-stop execution time before a switching occurs. A value of x will let the thread execute for x-1 to x milliseconds before switching to another thread.
Lua return values
result: 1 if the timing was set, 0 if it was not set (e.g. because the function was called from the main or application thread), or -1 in case of an error.

simResumeThreads / sim.resumeThreads 恢复某个线程

Description In conjunction with sim.setThreadResumeLocation, sim.resumeThreads allows specifying when and in which order threads are resumed. By default, V-REP doesn't use "regular" threads, but something similar to hybrid threads (which behave like coroutines, but can also behave like regular threads). This allows much more flexibility and execution control of the threads. Once a thread switched to another thread, it will resume execution at the beginning of next simulation pass by default. In order to also have full synchronization control between threads, you can assign a resume location and order to each thread. When sim.resumeThreads(x) is called, all threads that were assigned a resume location of x will be resumed. See also sim.setThreadResumeLocation, sim.setThreadSwitchTiming, sim.switchThread and sim.setThreadIsFree. This function can only be called in the main script.

simSetThreadResumeLocation / sim.setThreadResumeLocation

Description Allows specifying when and in which order child script threads are resumed. If the current script doesn't run in a thread (i.e. if it runs in the application main thread), this function has no effect. By default, V-REP doesn't use "regular" threads, but something similar to hybrid threads (which behave like coroutines, but can also behave like regular threads). This allows much more flexibility and execution control of the threads. Once a thread switched to another thread, it will resume execution when the main script calls sim.resumeThreads with the corresponding argument, which represents a child script thread resume location. In order to also have full synchronization control between threads, you can assign a resume location and order to each thread with this function. See also sim.setThreadSwitchTiming, sim.setThreadAutomaticSwitch, sim.switchThread and sim.setThreadIsFree.
C synopsis -
C parameters -
C return value -
Lua synopsis number result=sim.setThreadResumeLocation(number location,number order)
Lua parameters
location: a child script thread resume location.
order: a script resume or execution order.
Lua return values
result: 1 if the command was applied, 0 if it was not (e.g. because the function was called from the main or application thread), or -1 in case of an error.

4.举例说明:

创建分成以下四种情况:

4.1

function sysCall_threadmain()local lastSimulationTime=sim.getSimulationTime()local simulationStep=sim.getSimulationTimeStep()while true dolocal cnt=0-- Inner loop:while sim.getSimulationTime()==lastSimulationTime docnt=cnt+1endprintf('Inner loop executed %i times for one simulation step.',cnt)local dt=sim.getSimulationTime()-lastSimulationTimeprintf('Thread was interrupted %i times since last simulation step.',math.floor((dt/simulationStep)+0.5))lastSimulationTime=sim.getSimulationTime()end
end
没有把线程自动切换关闭,也不使用sim.switchthread(),内循环会执行很多次,而中断只有一次。

4.2

function sysCall_threadmain()local lastSimulationTime=sim.getSimulationTime()local simulationStep=sim.getSimulationTimeStep()while true dolocal cnt=0-- Inner loop:while sim.getSimulationTime()==lastSimulationTime docnt=cnt+1sim.switchThread()endprintf('Inner loop executed %i times for one simulation step.',cnt)local dt=sim.getSimulationTime()-lastSimulationTimeprintf('Thread was interrupted %i times since last simulation step.',math.floor((dt/simulationStep)+0.5))lastSimulationTime=sim.getSimulationTime()end
end
线程自动切换没有关闭,使用了 sim.switchThread(),内循环只进行一次,中断也只进行一次。
4.3
function sysCall_threadmain()local lastSimulationTime=sim.getSimulationTime()local simulationStep=sim.getSimulationTimeStep()while true dolocal cnt=0-- Inner loop:while sim.getSimulationTime()==lastSimulationTime dofor j=1,100000,1 do end -- delay loopcnt=cnt+1sim.switchThread()endprintf('Inner loop executed %i times for one simulation step.',cnt)local dt=sim.getSimulationTime()-lastSimulationTimeprintf('Thread was interrupted %i times since last simulation step.',math.floor((dt/simulationStep)+0.5))lastSimulationTime=sim.getSimulationTime()end
end

没有关闭线程的自动切换,又增加了for 循环,内循环只进行了一次,但是由于线程会自动切换,中断发生了许多次。

4.4

function sysCall_threadmain()sim.setThreadAutomaticSwitch(false)local lastSimulationTime=sim.getSimulationTime()local simulationStep=sim.getSimulationTimeStep()while true dolocal cnt=0-- Inner loop:while sim.getSimulationTime()==lastSimulationTime dofor j=1,100000,1 do end -- delay loopcnt=cnt+1sim.switchThread()endprintf('Inner loop executed %i times for one simulation step.',cnt)local dt=sim.getSimulationTime()-lastSimulationTimeprintf('Thread was interrupted %i times since last simulation step.',math.floor((dt/simulationStep)+0.5))lastSimulationTime=sim.getSimulationTime()end
end
使用sim.setThreadAutomaticSwitch(false)关闭线程的自动切换,虽然同样是增加了for 循环,但是打印结果显示,内循环只会发生一次,中断也只发生一次(由于 sim.switchThread()而发生的一次).

参考:

进程、线程、多线程相关总结

Clarification about "Thread related functionality"

V-REP Forum - Search

how to simulate precise interrupt timing in V-Rep?

Lua学习笔记-9.4章-非抢占式的多线程 -

Vrep线程之间的切换相关推荐

  1. 线程之间的几种通信方式

    1. 什么是线程间的通信 线程间通信其实就是多个线程在操作同一个资源时,多个线程之间不断切换执行时所发出的信号.例如:需要创建两个线程,一条线程只打印1-26的数字,另一条只打印A-Z的字母,最终打印 ...

  2. 线程的创建 验证线程之间共享数据 守护线程 线程进程效率对比 锁 死锁 递归锁...

    线程(from threading import Thread):CPU调度的最小单位 线程的两种创建方式:方式一: 1 from threading import Thread 2 def f1(i ...

  3. 程序、进程、线程之间的区别

    1.   .net的公共语言运行时(CLR)能够区别两种不同类型的线程:前台线程和后台线程.前台线程与后台线程的区别: 应用程序必须运行完所有的前台线程才可以退出.而对于后台线程,应用程序则可以不考虑 ...

  4. 线程的状态转换、sleep()、wait()、yeild()、终止线程的方法、线程之间的协作(join()、wait() notify() notifyAll()、await() signal() )

    1.线程的状态转换 1.1 新建(New) 创建后尚未启动 1.2 可运行(Runnable) 可能正在运行,也可能正在等待 CPU 时间片. 包含了操作系统线程状态中的 Running 和 Read ...

  5. 用户线程和内核线程之间的区别

    转载于http://col1.blog.163.com/blog/static/1909775192012719114033352/ 1 .内核级线程:切换由内核控制,当线程进行切换的时候,由用户态转 ...

  6. 安卓开发fragment之间的切换_Android开发必会的组件化技术—Android架构和提升必备...

    很多时候我们开发的时候,都需要新建项目,然后一个个底层模块去写,比如各种常见View,工具类,缓存模块等,经常进行这种重复的搬砖工作.主要还是因为我们在平时的开发过程中就没有注意分层.分模块.资源随意 ...

  7. Java多线程系列(二):线程的五大状态,以及线程之间的通信与协作

    在Java面试的时候,经常会问到Java并发编程相关的多线程.线程池.线程锁.线程通信等面试必考点,比如: Java并发编程系列:Java线程池的使用方式,核心运行原理.以及注意事项 Java并发编程 ...

  8. 线程知识点(一)—— 程序、进程、线程之间的区别与联系、Java的线程状态和生命周期

    1 程序.进程.线程之间的区别与联系 三者之间的形象化理解: * 程序:代码实现了功能,就是程序,是静态的: * 进程:执行中的程序就是进程,是动态的: * 线程:进程内的一个执行单元,也是进程内的可 ...

  9. Linux 系统进程、线程之间的爱恨纠葛...

    当一个程序开始执行后,在开始执行到执行完毕退出这段时间内,它在内存中的部分就叫称作一个进程. Linux 是一个多任务的操作系统,也就是说,在同一时间内,可以有多个进程同时执行.我们大家常用的单CPU ...

最新文章

  1. 前端学习笔记(五)-JavaScript语法基本概念
  2. 数据库中日期大小的判断
  3. SharePoint 2013 Word 转换PDF服务介绍及示例
  4. O(n)级选排名第k位数(附上算法复杂度分析)
  5. 建模matlab的算法代码呀,数学建模算法打包
  6. 探究call 和 apply 的原理
  7. python安装opencv2.4.9_Python学习之一:Python2.7与opencv2.4安装配置
  8. ib_logfile和mysql_bin_mysql的innodb中事务日志ib_logfile
  9. arcgis合并tif影像_ARCGIS多种影像裁剪
  10. LoadRunner Vuser测试脚本添加前置条件举例
  11. druid.io index_realtime任务的hand off:仍然是源码+log说清楚
  12. 选用pg的优点和缺点
  13. 微信公众平台之使用PPT制作图片
  14. 【附源码】计算机毕业设计SSM天气预报系统
  15. 【阅读】Extrinsic 6DoF Calibration of 3D LiDAR and Radar
  16. python的驻留机制
  17. 【ARM自学笔记】ARM7时钟简述及配置
  18. Pygame飞机大战(四)——创建己方飞机的类,并添加子弹吧
  19. android动态图制作,Android 教程:如何在手机上制作高质量的 GIF 图片
  20. 华为服务器怎么恢复系统,服务器恢复系统

热门文章

  1. [Oracle]如何查看一个数据文件是否是自动扩展
  2. 操作系统(4)-进程间通信
  3. spring data elasticsearch 对应 elasticsearch 版本
  4. linux桥接设置静态,centos6.10 桥接模式下配置静态ip
  5. php 路由实现_PHP操作路由器实现方法示例
  6. vmware 12 安装centos7网络配置
  7. Gradle实战-配置环境变量
  8. VSTO之旅系列(五):创建Outlook解决方案
  9. 企业级管理软件快速开发平台-完整的权限管理设计
  10. ShartPoin无法创建门户网站的问题