Skip to content

Commit 7d2ae4e

Browse files
Update Threading SKILL.md: Add Rule 3 banning synchronization and getInstance() from periodic loops
1 parent d391c20 commit 7d2ae4e

1 file changed

Lines changed: 55 additions & 34 deletions

File tree

  • .agents/skills/marslib-threading
Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,55 @@
1-
---
2-
name: marslib-threading
3-
description: Dictates the elite standard for writing custom java Thread instances in MARSLib, strictly enforcing time-unit sleeping and interrupt safeties to prevent loop lockups.
4-
---
5-
6-
# MARSLib Threading Standards
7-
8-
Any time you are tasked with creating a background loop (e.g., `PhoenixOdometryThread`, a Custom Coprocessor Listener, or I2C buffer queues) it must be perfectly thread-safe and adhere to MARSLib's `ProjectDoctor` linting standards.
9-
10-
## 1. No Infinite Loops
11-
NEVER write `while (true)` inside a `run()` loop. The JVM handles thread interruption automatically during RoboRIO code restarts or autonomous transitions.
12-
**Always use:**
13-
```java
14-
@Override
15-
public void run() {
16-
while (!Thread.currentThread().isInterrupted()) {
17-
// ... Logic ...
18-
}
19-
}
20-
```
21-
22-
## 2. No Raw Thread Sleeps
23-
ProjectDoctor explicitly flags `Thread.sleep(...)` as a dangerous blocking call because it's ambiguous what unit of time is being requested, often leading to 20ms delays becoming 20 second loop lockups.
24-
25-
**Always use `java.util.concurrent.TimeUnit`:**
26-
```java
27-
try {
28-
TimeUnit.MILLISECONDS.sleep(20);
29-
} catch (InterruptedException e) {
30-
Thread.currentThread().interrupt(); // Restore interrupt status
31-
break; // Safely exit the loop
32-
}
33-
```
34-
Never swallow the `InterruptedException`. You must properly re-assert the interrupt state to gracefully shut down the thread pool.
1+
---
2+
name: marslib-threading
3+
description: Dictates the elite standard for writing custom java Thread instances in MARSLib, strictly enforcing time-unit sleeping and interrupt safeties to prevent loop lockups.
4+
---
5+
6+
# MARSLib Threading Standards
7+
8+
Any time you are tasked with creating a background loop (e.g., `PhoenixOdometryThread`, a Custom Coprocessor Listener, or I2C buffer queues) it must be perfectly thread-safe and adhere to MARSLib's `ProjectDoctor` linting standards.
9+
10+
## 1. No Infinite Loops
11+
NEVER write `while (true)` inside a `run()` loop. The JVM handles thread interruption automatically during RoboRIO code restarts or autonomous transitions.
12+
**Always use:**
13+
```java
14+
@Override
15+
public void run() {
16+
while (!Thread.currentThread().isInterrupted()) {
17+
// ... Logic ...
18+
}
19+
}
20+
```
21+
22+
## 2. No Raw Thread Sleeps
23+
ProjectDoctor explicitly flags `Thread.sleep(...)` as a dangerous blocking call because it's ambiguous what unit of time is being requested, often leading to 20ms delays becoming 20 second loop lockups.
24+
25+
**Always use `java.util.concurrent.TimeUnit`:**
26+
```java
27+
try {
28+
TimeUnit.MILLISECONDS.sleep(20);
29+
} catch (InterruptedException e) {
30+
Thread.currentThread().interrupt(); // Restore interrupt status
31+
break; // Safely exit the loop
32+
}
33+
```
34+
Never swallow the `InterruptedException`. You must properly re-assert the interrupt state to gracefully shut down the thread pool.
35+
36+
## 3. Cache References in Constructor (No Hot Path Synchronization)
37+
Under zero circumstances should a 50Hz periodic loop (`updateInputs()`, `periodic()`, `execute()`) interact with a `synchronized` method or invoke `.getInstance()` of a continuous thread or Singleton. Doing so forces the fast periodic loop to compete for CPU lock availability with the thread's background loop, resulting in Lock Contention jitter.
38+
39+
**Always cache the Thread's exact memory address in the constructor:**
40+
```java
41+
public class MySwerveModule {
42+
// Hold a persistent hard reference to the memory location
43+
private final PhoenixOdometryThread odometryThread;
44+
45+
public MySwerveModule() {
46+
// Cross the synchronized bridge EXACTLY ONCE on boot
47+
this.odometryThread = PhoenixOdometryThread.getInstance();
48+
}
49+
50+
public void updateInputs() {
51+
// Direct, instantaneous memory poll with zero lock contention
52+
var data = this.odometryThread.getLatestData();
53+
}
54+
}
55+
```

0 commit comments

Comments
 (0)