Skip to content

Instantly share code, notes, and snippets.

@rbrott
Last active April 28, 2022 01:28
Show Gist options
  • Save rbrott/83c8c54dc1776fb91f2c2000af92ec29 to your computer and use it in GitHub Desktop.
Save rbrott/83c8c54dc1776fb91f2c2000af92ec29 to your computer and use it in GitHub Desktop.
Multithreading FTC SDK Hardware Calls

Multithreading FTC SDK hardware calls cannot improve call throughput and unpredictably increases call latency.

(Based on FTC SDK v7.1. You decide whether changes in subsequent releases compromise the argument.)

The bulk of time spent in a hardware call is waiting for a Lynx message response in the body of LynxRespondable#send() or LynxRespondable#sendReceive(). Both methods need to acquire the network lock before any data transmission occurs. Each collection of Lynx devices on the same USB bus has its own lock, so only one message can be sent and received at a time from that whole block of devices. One is therefore limited to the throughput of a single thread of execution.

Worse, multithreading calls may unpredictably increase their latency over the single-threaded case. Imagine two innocuous threads running in parallel.

// odometry thread
while (true) {
  val leftPos = leftEncoder.getPosition() // 0
  val rightPos = rightEncoder.getPosition() // 2 
  val strafePos = strafeEncoder.getPosition() // 4
  updatePoseEstimate(leftPos, rightPos, strafePos)
}

// turret control thread
while (true) {
  val turretPos = turretMotor.getPosition() // 1
  val turretPower = updatePidController(turretPos)
  turretMotor.setPower(turretPower) // 3
}

Under normal conditions (fair scheduler and locks), the method calls may return in the order given by the comments. The interleaving means extra time passes between odometry position measurements that are assumed to be simultaneous, degrading odometry accuracy. It also adds lag into the turret PID control loop by delaying the turret's PID command from being sent. The problem is only exacerbated by additional threads, and there are similar variability issues even when critical sections are imposed with further synchronization.

Threads are also generally undesirable for other reasons:

  • Concurrent programming is difficult. Here's the first paragraph of the Preface of Brian Goetz's essential book Java Concurrency in Practice:

    At this writing, multicore processors are just now becoming inexpensive enough for midrange desktop systems. Not coincidentally, many development teams are noticing more and more threading-related bug reports in their projects. In a recent post on the NetBeans developer site, one of the core maintainers observed that a single class had been patched over 14 times to fix threading-related problems. Dion Almaer, former editor of TheServerSide, recently blogged (after a painful debugging session that ultimately revealed a threading bug) that most Java programs are so rife with concurrency bugs that they work only “by accident”.

  • Exceptions in threads aren't logged and reported by default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment