- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在java程序中创建了三个线程。一个是主程序,另外两个是扩展Thread的类。主线程代表机器的 Controller 。另一个线程是执行器,第三个线程是传感器。 Controller 在其自己的类中设置变量,该变量由执行器线程读取。执行器根据指令执行一定的 Action 并更新自身的内部变量。这些依次由传感器线程读取,传感器线程读取执行器变量(代表现实世界的 Action )并设置其自己的内部变量,这些变量又由 Controller 读取,我们又回到了原点。然后 Controller 根据新感知的世界等设置变量。
执行器处于永久循环中,每个循环 hibernate 100 毫秒。传感器也处于一个永恒循环中,每个循环 sleep 20 毫秒。
系统几乎可以工作了。主循环将错过传感器的更新,除非我也为其添加 sleep 。我现在的问题是为什么会这样?即使 sleep(0) 也能让系统正常工作。我已将该语句放置在 PerformJob(Job input) while 循环内。没有 sleep 调用的 java 主线程与具有 sleep 调用的同一线程的行为有何不同?并发对我来说是一个相当新的主题。
这是我正在使用的代码:
主要:
public class Main {
public static void main(String[] args) {
Controller Press = new Controller();
Press.processUnits(1); // no reset code at the moment, only use 1 at a time
Press.shutdownThreads();
}
}
Controller :
import java.util.LinkedList;
public class Controller extends Thread {
// Constants
static final int STATE_WAITING = 0;
static final int STATE_MOVE_ARMS = 1;
static final int STATE_MOVE_PRESS = 2;
static final int LOADINGARM = 2;
static final int UNLOADINGARM = 1;
static final int NOARM = 0;
static final boolean EXTEND = true;
static final boolean RETRACT = false;
private enum Jobs {
EXTENDRETRACT, ROTATE, MAGNETONOFF, PRESSLOWERRAISE
}
// Class variables
private int currentState;
// Component instructions
private int armChoice = 0;
private boolean bool = false; // on, up, extend / off, down, retract
private boolean[] rotInstr = {false, false}; // {rotate?, left true/right false}
private boolean errorHasOccurred = false;
private boolean pressDir = false;
private Sensors sense = null;
private Actuators act = null;
private LinkedList<Job> queue = null;
// Constructor
public Controller() {
act = new Actuators(0.0f, this);
sense = new Sensors();
act.start();
sense.start();
currentState = STATE_WAITING;
queue = new LinkedList<Job>();
}
// Methods
int[] getArmInstructions() {
int extret = (bool) ? 1 : 0;
int[] ret = {armChoice, extret};
return ret;
}
boolean[] getRotation() {
return rotInstr;
}
int getControllerState() {
return currentState;
}
boolean getPressDirection() {
return pressDir;
}
public boolean processUnits(int nAmount) {
if (run(nAmount)) {
System.out.println("Controller: All units have been processed successfully.");
return true;
} else { // procUnits returning false means something went wrong
System.out.println("Controller: An error has occured. The process cannot complete.");
return false;
}
}
/*
* This is the main run routine. Here the controller analyses its internal state and its sensors
* to determine what is happening. To control the arms and press, it sets variables, these symbolize
* the instructions that are sent to the actuators. The actuators run in a separate thread which constantly
* reads instructions from the controller and act accordingly. The sensors and actuators are dumb, they
* will only do what they are told, and if they malfunction it is up to the controller to detect dangers or
* malfunctions and either abort or correct.
*/
private boolean run(int nUnits) {
/*
Here depending on internal state, different actions will take place. The process uses a queue of jobs
to keep track of what to do, it reads a job, sets the variables and then waits until that job has finished
according to the sensors, it will listen to all the sensors to make sure the correct sequence of events is
taking place. The controller reads the sensor information from the sensor thread which runs on its own
similar to the controller.
In state waiting the controller is waiting for input, when given the thread cues up the appropriate sequence of jobs
and changes its internal state to state move arms
In Move arms, the controller is actively updating its variables as its jobs are performed,
In this state the jobs are, extend, retract and rotate, pickup and drop.
From this state it is possible to go to move press state once certain conditions apply
In Move Press state, the controller through its variables control the press, the arms must be out of the way!
In this state the jobs are press goes up or down. Pressing is taking place at the topmost position, middle position is for drop off
and lower is for pickup. When the press is considered done, the state reverts to move arms,
*/
//PSEUDO CODE:
//This routine being called means that there are units to be processed
//Make sure the controller is not in a blocking state, that is, it shut down previously due to errors
//dangers or malfunctions
//If all ok - ASSUMED SO AS COMPONENTS ARE FAULT FREE IN THIS VERSION
if (!errorHasOccurred) {
//retract arms
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//System.out.println("Jobs added");
//while there are still units to process
for (;nUnits != 0; nUnits--) {
//move the press to lower position, for unloading
currentState = STATE_MOVE_PRESS;
//rotate to pickup area and pickup the metal, also pickup processed
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, EXTEND));
performWork();
//retract and rotate
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//state change, press moves to middle position
currentState = STATE_MOVE_PRESS;
//state change back, put the metal on the press, drop processed and pull arms back
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//state change, press the metal in upper position
currentState = STATE_MOVE_PRESS;
//repeat until done
}
//unload final piece
//move the press to lower position for unload
//rotate and pickup processed piece
//drop it off at unloading and wait for more orders
currentState = STATE_WAITING;
}
return true;
}
private boolean performWork() {
while (!queue.isEmpty()) {
performJob(queue.removeFirst());
}
return true;
}
private boolean performJob(Job input) {
//The purpose of this function is to update the variables and wait until they are completed
// read in the job and check appropriate sensors
boolean[] data = sense.getSensorData(); // LExt, LRet, UlExt, UlRet
printBools(data);
int Instruction = input.Instruction;
boolean skipVars = false;
if (input.Job == Jobs.EXTENDRETRACT) {
if (currentState != STATE_MOVE_ARMS){
System.out.println("Wrong state in performJob. State is "+currentState+" expected "+STATE_MOVE_ARMS);
return false;
}
if ((Instruction == LOADINGARM) && (input.Bool)) skipVars = data[0];
if ((Instruction == LOADINGARM) && (!input.Bool)) skipVars = data[1];
if ((Instruction == UNLOADINGARM) && (input.Bool)) skipVars = data[2];
if ((Instruction == UNLOADINGARM) && (!input.Bool)) skipVars = data[3];
}
if (!skipVars) {
// if sensors not at intended values, update correct variables
System.out.println("Controller: Did not skip vars");
switch (input.Job) {
case EXTENDRETRACT:
armChoice = (Instruction == LOADINGARM) ? LOADINGARM : UNLOADINGARM;
bool = input.Bool;
break;
case ROTATE:
break;
case MAGNETONOFF:
break;
case PRESSLOWERRAISE:
break;
default:
System.out.println("Default called in performJob()");
break;
}
}
// listen to sensors until completed
boolean done = false;
System.out.println("Waiting for sensor data.");
//System.out.print("Instruction is "+Instruction+" and bool is "); if (input.Bool) System.out.print("true\n"); else System.out.print("false\n");
while (!done) {
data = sense.getSensorData();
// REMOVING THIS TRY STATEMENT BREAKS THE PROGRAM
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
System.out.println("Main thread couldn't sleep.");
}
// Check appropriate sensors
if (input.Job == Jobs.EXTENDRETRACT) {
if ((Instruction == LOADINGARM) && (input.Bool)) done = data[0];
if ((Instruction == LOADINGARM) && (!input.Bool)) done = data[1];
if ((Instruction == UNLOADINGARM) && (input.Bool)) done = data[2];
if ((Instruction == UNLOADINGARM) && (!input.Bool)) done = data[3];
}
}
// reset all variables
armChoice = 0;
bool = false;
// when done return
System.out.println("Finished "+input.Job);
return true;
}
public void shutdownThreads() {
sense.shutDown();
act.shutDown();
}
private class Job {
// Class variables
Jobs Job;
int Instruction;
boolean Bool; // used for directions, up/down, left/right, extend/retract
// Constructor
Job(Jobs newJob, int newInstruction, boolean dir) {
Job = newJob;
Instruction = newInstruction;
Bool = dir;
}
}
private void printBools(boolean[] input) {
System.out.println();
for (int i = 0; i < input.length; i++) {
if (input[i]) System.out.print("true "); else System.out.print("false ");
}
System.out.println();
}
}
执行器:
public class Actuators extends Thread {
// Constants
private final int ARM = 0, ROTATE = 0; // array indexes - which arm, rotate yes/no?
private final int DIR = 1, ROTDIR = 1; // array indexes - which direction ext/ret, rotate direction
private final int EXT = 1;//, RET = 0;
private final double ARM_SPEED = 5.0;
// Class variables
private Controller Owner = null;
private boolean run = true;
// Constructor
Actuators(float nPos, Controller Owner) {
Reality.changeAngle(nPos);
this.Owner = Owner;
}
// Methods
private void rotate(boolean dir) {
float nAngle = dir ? 0.1f : -0.1f;
Reality.changeAngle(nAngle);
}
public void run() {
while (run) {
try {
sleep(100);
} catch (InterruptedException e) {
System.out.println("Actuators couldn't sleep");
}
// read variables in controller
int nState = Owner.getControllerState();
if (nState == Controller.STATE_MOVE_ARMS) {
boolean[] rot = Owner.getRotation();
if (rot[ROTATE]) { // Rotation?
rotate(rot[ROTDIR]);
} else { // or arm extensions
int[] instr = Owner.getArmInstructions();
if (instr[ARM] != Controller.NOARM) { // 0 = no arm movement
//System.out.println("Actuator arm is "+instr[ARM]);
double dir = (instr[DIR] == EXT) ? ARM_SPEED : -ARM_SPEED; // 1 = extend, 0 = retract
Reality.changeArmLength(instr[ARM], dir);
}
}
}
}
}
void shutDown() {
run = false;
}
}
Reality 是一个由静态字段和方法组成的类,由执行器写入并由传感器读取。
public class Reality {
// Constants
static private final double EXTEND_LIMIT = 100.0;
static private final double RETRACT_LIMIT = 0.0;
// Variables
private static float ArmsAngle = 0.0f;
// Read by Sensor
static double LoadingArmPos = 0.0;
static double UnloadingArmPos = 0.0;
// Methods
static void changeAngle(float newAngle) {
ArmsAngle = ArmsAngle + newAngle;
if ((ArmsAngle < 0.0f) || (ArmsAngle > 90.0f))
System.out.println("Reality: Unallowed Angle");
}
static void changeArmLength(int nArm, double dPos) { // true = extend, false = retract
switch (nArm) {
case Controller.LOADINGARM:
LoadingArmPos += dPos;
checkArmPos(LoadingArmPos);
break;
case Controller.UNLOADINGARM:
UnloadingArmPos += dPos;
checkArmPos(UnloadingArmPos);
break;
default:
System.out.println("Arm other than 2 (load) or 1 (unload) in changeArmLength in Reality");
break;
}
}
static float senseAngle() {
return ArmsAngle;
}
static private boolean checkArmPos(double dPos) {
// Allowed positions are 100.0 to 0.0
if ((dPos > EXTEND_LIMIT) || (dPos < RETRACT_LIMIT)) {
System.out.println("Arm position impossible in reality. Is "+dPos);
return true;
} else {
return false;
}
}
}
最后是传感器:
public class Sensors extends Thread {
// Constants
private final double EXTENDED = 100.0;
private final double RETRACTED = 0.0;
private final double MARGIN = 0.1;
// Class Variables
private boolean run = true;
// Read by Controller
private boolean LoadingExtended = true;
private boolean LoadingRetracted = true;
private boolean UnloadingExtended = true;
private boolean UnloadingRetracted = true;
// Constructor
Sensors() {
LoadingExtended = false;
LoadingRetracted = true;
UnloadingExtended = false;
UnloadingRetracted = true;
}
// Methods
boolean senseLoadingExtended() {
return (Math.abs(Reality.LoadingArmPos - EXTENDED) < MARGIN);
}
boolean senseLoadingRetracted() {
return (Math.abs(Reality.LoadingArmPos - RETRACTED) < MARGIN);
}
boolean senseUnloadingExtended() {
return (Math.abs(Reality.UnloadingArmPos - EXTENDED) < MARGIN);
}
boolean senseUnloadingRetracted() {
return (Math.abs(Reality.UnloadingArmPos - RETRACTED) < MARGIN);
}
// called by Controller
boolean[] getSensorData() {
boolean[] ret = {LoadingExtended, LoadingRetracted, UnloadingExtended, UnloadingRetracted};
return ret;
}
// Sensor primary loop
public void run() {
while (run) {
try {
sleep(20);
}
catch (InterruptedException e) {
System.out.println("Sensors couldn't sleep");
}
LoadingExtended = senseLoadingExtended();
LoadingRetracted = senseLoadingRetracted();
UnloadingExtended = senseUnloadingExtended();
UnloadingRetracted = senseUnloadingRetracted();
}
}
void shutDown() {
run = false;
}
}
在此版本中并非读取所有字段和函数。该程序是对以前主要使用函数调用的单线程应用程序的改造。为了便于阅读,我对代码进行了一些清理。即使这不是最初的问题,也欢迎提出建设性的设计意见。确实发生了一些可疑的事情。我通常不是一个迷信的编码员,但我可以例如用 System.out.println() 调用替换 sleep 调用,并且程序将运行。
最佳答案
Google 的“生产者消费者队列”。
不要使用 sleep() 进行线程间通信,除非您想要延迟、效率低下和丢失数据。有更好的机制可以避免 sleep() 并尝试直接从某些共享/锁定对象读取有效数据。
如果您使用命令/请求/数据加载“通信”对象,将它们排队到其他线程并立即创建另一个通信对象用于后续通信,您的线程间通信将快速且安全,没有 sleep() 延迟并且任何线程都不可能读取过时的数据或被另一个线程更改的数据。
关于java - 线程缺少其他线程的更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11406666/
我正在尝试在 map 上绘制一些疾病事件数据的位置。 我用它来导入数据: ByTown% addProviderTiles("CartoDB.Positron")%>% addPolygons
我有一个文件调用 find.js,我使用 node find.js 运行,我的节点是版本 10 我不知道为什么我无法使用 async await。 const axios = require("axi
我有一个项目作为引用添加到 System.Web。 但是,它似乎无法获取 HttpContext。这样做: Imports System.Web _ApplicationBase = HttpCont
在互联网上找到这段代码,出于某种原因它缺少 while 循环逻辑“while(i....)”,虽然我找到了 PigLatin* 问题的其他可行解决方案,但我真的很想了解这个正在工作。 *PigLati
我工作了一整天来运行 Xampp 并在其上安装 TYPO3。现在我登录到后端,但没有显示许多管理模块,例如模板、访问等。 - 一定是我做错了什么,但我不知道。 these are the module
你好 我有编译这个问题 \begin{equation} J = \sum_{j=1}^{C} \end{equation} 我不断收到错误 missing $ inserted 这很奇怪,因
我正在尝试使用 SQLite CLI,但无法获得 generate_series功能来工作。我可以按照文档中的建议使用递归 CTE 对其进行模拟,但我似乎无法获得该链接中的任何示例。这是我的 sess
我目前正在开发我想要的软件,而软件正在安装,它可以在后台为软件创建 native 图像。 我正在考虑使用 NGEN 并将进程优先级设置为低,因为我不希望它消耗 100% CPU。但是我发现我的计算机上
我想使用 Xcodes Instruments 进行 UI 自动化测试。但似乎缺少“自动化”。我怎样才能添加这个? 最佳答案 如果您想使用自动化仪器,请使用 Xcode 7.3。 Apple 在 Xc
我目前在 JS 开发中迈出了一小步,并编写了以下链接添加器: const button = document.getElementById('button') const listdiv = docu
此代码有什么问题: NSError *error = nil; [SFHFKeychainUtils deleteItemForUsername:@"IAPNoob01" andServiceName
出于某种原因,在安装和配置(我认为)一切之后,com.adobe.utils.AGALMiniAssembler 不见了,其他一切正常。 我认为我已尽一切努力让孵化器正常工作,但显然我错过了一步。 如
我有一个名为 new 的方法。调用 new 时,我传递了一个参数,但是当我运行应用程序时,出现没有参数或参数为空的错误。 StepReader.pm package StepReader; use s
安装 gtk 1.2(包名 gtk1)和 macports chokes 在最终的 make 中,在 libintl.h 的第 440 行。 extern locale_t libintl_newlo
我用按钮创建表格。 这是javascript代码: function layersListTable(layers) { var content =''; $.each($(layer
我在使用此 javascript 时遇到此错误,任何人都可以帮我弄清楚我做错了什么吗? $(this).prepend('Check availability »'); 它给我错误 mis
我有一个独立的工具链 NDK13b、api19、llvm 3.8 编译器、arm 32 位、带有 libcpp(llvm C++ 库) 我想避免依赖 libgcc,所以我构建了 compiler-rt
我按照一些教程使用 phonegap 的条形码扫描器插件。但是当我从现有源创建一个新的 android 项目来创建条码库时 (step 6 in this page)我收到错误:“AndroidMan
我现在尝试在 Eclipse 中打开我的布局 xml 文件。我只得到错误 No XML content. Please add a root view or layout to your docume
我的 android-sdk-windows\tools 目录中缺少层次结构查看器工具。 工具链接: http://developer.android.com/guide/developing/too
我是一名优秀的程序员,十分优秀!