๐Ÿ’ป Programming ยท Engineer ยท Intermediate โ†’ Advanced

PROS Tasks & Multitasking

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