πŸ’» Programming Β· Engineer Β· Intermediate β†’ Advanced

PROS Tasks & Multitasking

πŸ—ΊοΈ Flowchart β€” PROS task lifecycle

PROS tasks are background workers β€” like having multiple control loops running at once. Use them when you need something to happen independent of opcontrol/auton.

flowchart TD
    Create([pros::Task task_handle]) --> Args[Pass function + args
also priority + stack size] Args --> Running[Task is running
repeats its body in a loop] Running --> Q1{Need to pause?} Q1 -->|"Yes"| Suspend[task_handle.suspend
task pauses, keeps state] Q1 -->|"No, kill it"| Remove[task_handle.remove
task is destroyed] Q1 -->|"Continue"| Running Suspend --> Q2{Resume?} Q2 -->|"Yes"| Resume[task_handle.resume
continues from where it paused] Q2 -->|"No, kill it"| Remove Resume --> Running Remove --> Gone([Task destroyed
can't be resumed]) style Create fill:#1e293b,stroke:#22d3ee,stroke-width:2px,color:#e2e8f0 style Gone fill:#1e293b,stroke:#22c55e,stroke-width:2px,color:#e2e8f0 style Q1 fill:#fbbf24,color:#0f172a,stroke:#fbbf24 style Q2 fill:#fbbf24,color:#0f172a,stroke:#fbbf24

The bridge between inline concurrent actions and real task architecture. Run your intake, sensors, and autonomous simultaneously β€” without blocking your main loop.

Before this guide: Read concurrent-actions.html. Tasks are for situations where inline pid_wait_until patterns aren't enough β€” typically when a subsystem needs to run continuously and independently of whatever the main code is doing.
πŸ“– What is a Task?

A pros::Task is a separate thread of execution. It runs its own function loop in parallel with main. The PROS kernel schedules tasks based on priority and gives each a slice of CPU time every millisecond. You can have multiple tasks running simultaneously β€” PROS handles the switching.

⚑ Basic Task Syntax
// Task function β€” must be void and take void*
void intakeTask(void* param) {
  while (true) {
    if (intakeWanted) {
      intake.move_velocity(600);
    } else {
      intake.brake();
    }
    pros::delay(10);  // ALWAYS delay β€” never spin-wait
  }
}

// Start the task β€” do this once in initialize() or autonomous()
pros::Task myIntake(intakeTask);
Always include pros::delay() inside every task loop. A task without delay will spin at full CPU speed and starve other tasks β€” including your drive code.
πŸ”§ Real Example β€” Intake + Autonomous Together
// globals.hpp
extern bool intakeOn;
extern bool intakeReverse;
pros::Mutex intakeMtx;  // protects shared state

// intake_task.cpp
void intake_task_fn(void*) {
  while (true) {
    intakeMtx.take(TIMEOUT_MAX);
    bool on = intakeOn;
    bool rev = intakeReverse;
    intakeMtx.give();

    if (on) {
      intake.move_velocity(rev ? -600 : 600);
    } else {
      intake.brake();
    }
    pros::delay(10);
  }
}

// autonomous() β€” drive and intake run at the same time
void autonomous() {
  pros::Task it(intake_task_fn);

  // Turn on intake, then immediately start driving
  intakeMtx.take(TIMEOUT_MAX);
  intakeOn = true;
  intakeMtx.give();

  chassis.pid_drive_set(24, 110);
  chassis.pid_wait();  // intake runs during this wait

  intakeMtx.take(TIMEOUT_MAX);
  intakeOn = false;
  intakeMtx.give();
}
πŸ” When Do You Need a Mutex?

A mutex (mutual exclusion lock) prevents two tasks from reading and writing a shared variable at the same moment. Without one, you can get data corruption β€” your task reads a value halfway through main updating it.

⚠ The 3 Most Common Task Bugs
❌ Task runs once and dies (no while loop)
Symptom: Intake activates briefly at auton start then stops. Fix: Every task function must have while(true) with a pros::delay(10) inside. Without the loop, the function exits and the task ends.
❌ Robot becomes unresponsive or crashes
Symptom: Robot freezes mid-auton or driver control stops responding. Fix: Missing pros::delay() in a task loop. Add pros::delay(10); as the last line of every task's while loop, always.
❌ Variable changes aren't seen by the task
Symptom: You set intakeOn = true in autonomous but the intake task doesn't respond. Fix: Declare shared variables as volatile or use a mutex. The compiler may optimize away reads of non-volatile variables in tight loops.
πŸ—‚ Task vs. Inline β€” When to Use Each
Pattern Use When
pid_wait_until()You want to trigger something mid-movement (e.g., extend arm at 12 inches into a 24-inch drive)
pros::TaskA subsystem needs to run continuously regardless of what else is happening (intake, sensor logging, state machines)
pros::delay() in opcontrolReading controller inputs in the main opcontrol loop β€” 20ms delay gives 50Hz update rate
⚙ STEM Highlight Computer Science: Concurrent Programming & Mutex Synchronization
PROS Tasks apply concurrent programming — executing multiple code paths simultaneously on a shared-memory system. Concurrency introduces race conditions: when two tasks access the same sensor without synchronization, read/write operations can interleave, producing unpredictable values. The solution is a mutex: only one task can hold the mutex at a time, serializing access to shared resources.
🎤 Interview line: “We use PROS Tasks for sensor monitoring and drive control simultaneously, with mutexes protecting shared sensor variables. When we first implemented concurrent tasks without synchronization, we saw intermittent erratic sensor readings — the classic symptom of a race condition. Adding mutex protection eliminated the issue. We documented this in our programming log because it demonstrates advanced concurrency understanding.”
You add a PROS Task for continuous sensor monitoring. The main autonomous reads erratic sensor values. What is the most likely cause?
⬛ Tasks run too slowly to capture sensor data in real time
⬛ The Task and main thread access the same sensor concurrently without synchronization — a race condition produces inconsistent reads
⬛ PROS Tasks cannot access sensors — only the main function can
📝
Notebook entry tip: Build & Program — Orange slide — Write a programming architecture entry when you first implement PROS Tasks: which subsystems run as tasks, why they need concurrent execution, and how you prevent race conditions (mutexes, task priorities). Documenting your concurrency design shows judges university-level CS thinking applied to your robot — an impressive and rarely seen notebook entry.
← ALL GUIDES