RTOS Facilities C++ API module

Files

file rtos.hpp

Classes

class pros::rtos::Task

Functions

Task(task_fn_t function, void* parameters = nullptr, std::uint32_t prio = TASK_PRIORITY_DEFAULT, std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "")
Creates a new task and add it to the list of tasks that are ready to run.
Task(task_fn_t function, void* parameters, const char* name)
Creates a new task and add it to the list of tasks that are ready to run.
template<class F>
static task_t create(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "")
Creates a new task and add it to the list of tasks that are ready to run.
template<class F>
static task_t create(F&& function, const char* name)
Creates a new task and add it to the list of tasks that are ready to run.
template<class F>
Task(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "") explicit
Creates a new task and add it to the list of tasks that are ready to run.
template<class F>
Task(F&& function, const char* name)
Creates a new task and add it to the list of tasks that are ready to run.
Task(task_t task) explicit
Create a C++ task object from a task handle.
static Task current()
Get the currently running Task.
Task& operator=(task_t in)
Creates a task object from the passed task handle.
void remove()
Removes the Task from the RTOS real time kernel's management.
std::uint32_t get_priority()
Gets the priority of the specified task.
void set_priority(std::uint32_t prio)
Sets the priority of the specified task.
std::uint32_t get_state()
Gets the state of the specified task.
void suspend()
Suspends the specified task, making it ineligible to be scheduled.
void resume()
Resumes the specified task, making it eligible to be scheduled.
const char* get_name()
Gets the name of the specified task.
operator task_t() explicit
Convert this object to a C task_t handle.
std::uint32_t notify()
Sends a simple notification to task and increments the notification counter.
void join()
Utilizes task notifications to wait until specified task is complete and deleted, then continues to execute the program.
std::uint32_t notify_ext(std::uint32_t value, notify_action_e_t action, std::uint32_t* prev_value)
Sends a notification to a task, optionally performing some action.
static std::uint32_t notify_take(bool clear_on_exit, std::uint32_t timeout)
Waits for a notification to be nonzero.
bool notify_clear()
Clears the notification for a task.
static void delay(const std::uint32_t milliseconds)
Delays the current task for a specified number of milliseconds.
static void delay_until(std::uint32_t*const prev_time, const std::uint32_t delta)
Delays the current Task until a specified time.
static std::uint32_t get_count()
Gets the number of tasks the kernel is currently managing, including all ready, blocked, or suspended tasks.
static time_point now()
Gets the current time.
Mutex()
Mutex(const Mutex&) deleted
Mutex(Mutex&&) deleted
Mutex& operator=(const Mutex&) deleted
Mutex& operator=(Mutex&&) deleted
bool take()
Takes and locks a mutex indefinetly.
bool take(std::uint32_t timeout)
Takes and locks a mutex, waiting for up to a certain number of milliseconds before timing out.
bool give()
Unlocks a mutex.
void lock()
Takes and locks a mutex, waiting for up to TIMEOUT_MAX milliseconds.
void unlock()
Unlocks a mutex.
bool try_lock()
Try to lock a mutex.
template<typename Rep, typename Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& rel_time)
Takes and locks a mutex, waiting for a specified duration.
template<typename Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& abs_time)
Takes and locks a mutex, waiting until a specified time.

Typedefs

using rep = std::uint32_t
using period = std::milli
using duration = std::chrono::duration<rep, period>
using time_point = std::chrono::time_point<Clock>

Variables

task_t task
const bool is_steady
std::shared_ptr<std::remove_pointer_t<mutex_t>> mutex

Function documentation

Task(task_fn_t function, void* parameters = nullptr, std::uint32_t prio = TASK_PRIORITY_DEFAULT, std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "")

Creates a new task and add it to the list of tasks that are ready to run.

Parameters
function Pointer to the task entry function
parameters Pointer to memory that will be used as a parameter for the task being created. This memory should not typically come from stack, but rather from dynamically (i.e., malloc'd) or statically allocated memory.
prio The priority at which the task should run. TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used.
stack_depth The number of words (i.e. 4 * stack_depth) available on the task's stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct.
name A descriptive name for the task. This is mainly used to facilitate debugging. The name may be up to 32 characters long.

This function uses the following values of errno when an error state is reached: ENOMEM - The stack cannot be used as the TCB was not created.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(my_task_fn, (void*)"PROS");
}

Task(task_fn_t function, void* parameters, const char* name)

Creates a new task and add it to the list of tasks that are ready to run.

Parameters
function Pointer to the task entry function
parameters Pointer to memory that will be used as a parameter for the task being created. This memory should not typically come from stack, but rather from dynamically (i.e., malloc'd) or statically allocated memory.
name A descriptive name for the task. This is mainly used to facilitate debugging. The name may be up to 32 characters long.

This function uses the following values of errno when an error state is reached: ENOMEM - The stack cannot be used as the TCB was not created.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(my_task_fn, (void*)"PROS", "My Task");
}

template<class F>
static task_t create(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "")

Creates a new task and add it to the list of tasks that are ready to run.

Parameters
function Callable object to use as entry function
prio The priority at which the task should run. TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used.
stack_depth The number of words (i.e. 4 * stack_depth) available on the task's stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct.
name A descriptive name for the task. This is mainly used to facilitate debugging. The name may be up to 32 characters long.

This function uses the following values of errno when an error state is reached: ENOMEM - The stack cannot be used as the TCB was not created.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::c::task_t my_task = pros::Task::create(my_task_fn, (void*)"PROS");
}

template<class F>
static task_t create(F&& function, const char* name)

Creates a new task and add it to the list of tasks that are ready to run.

Parameters
function Callable object to use as entry function
name A descriptive name for the task. This is mainly used to facilitate debugging. The name may be up to 32 characters long.

This function uses the following values of errno when an error state is reached: ENOMEM - The stack cannot be used as the TCB was not created.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::c::task_t my_task = pros::Task::create(my_task_fn, "My Task");
}

template<class F>
Task(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "") explicit

Creates a new task and add it to the list of tasks that are ready to run.

Parameters
function Callable object to use as entry function
prio The priority at which the task should run. TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used.
stack_depth The number of words (i.e. 4 * stack_depth) available on the task's stack. TASK_STACK_DEPTH_DEFAULT is typically sufficient.
name A descriptive name for the task. This is mainly used to facilitate debugging. The name may be up to 32 characters long.

This function uses the following values of errno when an error state is reached: ENOMEM - The stack cannot be used as the TCB was not created.

Example

void initialize() {
  // Create a task function using lambdas
  auto task_fn = [](void* param) {
    printf("Hello %s\n", (char*)param);
  }

  pros::Task my_task(task_fn, (void*)"PROS", "My Task");
}

template<class F>
Task(F&& function, const char* name)

Creates a new task and add it to the list of tasks that are ready to run.

Parameters
function Callable object to use as entry function
name A descriptive name for the task. This is mainly used to facilitate debugging. The name may be up to 32 characters long.

This function uses the following values of errno when an error state is reached: ENOMEM - The stack cannot be used as the TCB was not created.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(
    [](void* param) {
      printf("Inside the task!\n");
    },
    "My Task"
  );
}

Task(task_t task) explicit

Create a C++ task object from a task handle.

Parameters
task A task handle from task_create() for which to create a pros::Task object.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::c::task_t my_task = pros::Task::create(my_task_fn, "My Task");

  pros::Task my_task_cpp(my_task);
}

static Task current()

Get the currently running Task.

Returns The currently running Task.

Example

void my_task_fn(void* param) {
  printf("The name of this task is \"%s\"\n", pros::Task::current().get_name()
}

void initialize() {
  pros::Task my_task(my_task_fn, pros::TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "My Task");
}

Task& operator=(task_t in)

Creates a task object from the passed task handle.

Parameters
in A task handle from task_create() for which to create a pros::Task object.

Example

void my_task_fn(void* param) {
  printf("The name of this task is \"%s\"\n", pros::Task::current().get_name()
}

void initialize() {
  pros::c::task_t my_task = pros::Task::create(my_task_fn, "My Task");

  pros::Task my_task_cpp = my_task;
}

void remove()

Removes the Task from the RTOS real time kernel's management.

This task will be removed from all ready, blocked, suspended and event lists.

Memory dynamically allocated by the task is not automatically freed, and should be freed before the task is deleted.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(my_task_fn, "My Task");
  
  my_task.remove();
}

std::uint32_t get_priority()

Gets the priority of the specified task.

Returns The priority of the task

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(my_task_fn, "My Task");

  printf("Task Priority: %d\n", my_task.get_priority());
}

void set_priority(std::uint32_t prio)

Sets the priority of the specified task.

Parameters
prio The new priority of the task

If the specified task's state is available to be scheduled (e.g. not blocked) and new priority is higher than the currently running task, a context switch may occur.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(my_task_fn, "My Task");

  Task.set_priority(pros::DEFAULT_PRIORITY + 1);
}

std::uint32_t get_state()

Gets the state of the specified task.

Returns The state of the task

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(my_task_fn, "My Task");

  printf("Task State: %d\n", my_task.get_state());
}

void suspend()

Suspends the specified task, making it ineligible to be scheduled.

Example

pros::Mutex counter_mutex;
int counter = 0;

void my_task_fn(void* param) {
  while(true) {
       counter_mutex.take(); // Mutexes are used for protecting shared resources
    counter++;
    counter_mutex.give();
    pros::delay(10);
  }
}

void opcontrol() {
  pros::Task task(my_task_fn, "My Task");

  while(true) {
    counter_mutex.take();
    if(counter > 100) {
      task_suspepend(task);
       }
    counter_mutex.give();
    pros::delay(10);
  }
}

void resume()

Resumes the specified task, making it eligible to be scheduled.

Example

void my_task_fn(void* param) {
  while(true) {
    // Do stuff
    pros::delay(10);
  }
}

pros::Task task(my_task_fn);

void autonomous() {
  task.resume();

  // Run autonomous , then suspend the task so it doesn't interfere run
  // outside of autonomous or opcontrol
  task.suspend();
}

void opcontrol() {
  task.resume();
  // Opctonrol code here
  task.suspend();
}

const char* get_name()

Gets the name of the specified task.

Returns A pointer to the name of the task

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(my_task_fn, "My Task");
  printf("Number of Running Tasks: %d\n", my_task.get_name());
}

operator task_t() explicit

Convert this object to a C task_t handle.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void initialize() {
  pros::Task my_task(my_task_fn, "My Task");

  pros::c::task_t my_task_c = (pros::c::task_t)my_task;
}

std::uint32_t notify()

Sends a simple notification to task and increments the notification counter.

Returns Always returns true.

See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for details.

Example

void my_task_fn(void* ign) {
  while(pros::Task::current_task().notify_take(true) == 0) {
    // Code while waiting
  }
  puts("I was unblocked!");
}

void opcontrol() {
  pros::Task my_task(my_task_fn);
  
  while(true) {
    if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) {
      my_task.notify();
    }
  }
}

void join()

Utilizes task notifications to wait until specified task is complete and deleted, then continues to execute the program.

Returns void

Analogous to std::thread::join in C++.

See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for details.

Example

void my_task_fn(void* ign) {
  lcd_print(1, "%s running", pros::Task::current_task().get_name());
  task_delay(1000);
  lcd_print(2, "End of %s", pros::Task::current_task().get_name());
}

void opcontrol() {
  pros::Task my_task(my_task_fn);
  pros::lcd::set_text(0, "Running task.");
  my_task.join();
  pros::lcd::lcd_set_text(3, "Task completed.");
}

std::uint32_t notify_ext(std::uint32_t value, notify_action_e_t action, std::uint32_t* prev_value)

Sends a notification to a task, optionally performing some action.

Parameters
value The value used in performing the action
action An action to optionally perform on the receiving task's notification value
prev_value A pointer to store the previous value of the target task's notification, may be NULL
Returns Dependent on the notification action. For NOTIFY_ACTION_NO_WRITE: return 0 if the value could be written without needing to overwrite, 1 otherwise. For all other NOTIFY_ACTION values: always return 0

Will also retrieve the value of the notification in the target task before modifying the notification value.

See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for details.

Example

void my_task_fn(void* param) {
  pros::Task task = pros::Task::current();

  while(true) {
    // Wait until we have been notified 20 times before running the code
    if(task.notify_take(false, TIMEOUT_MAX) == 20) {
      // ... Code to do stuff here ...

      // Reset the notification counter
      task.notify_clear();
    }
    delay(10);
     }
}

void opcontrol() {
  pros::Task task(my_task_fn);
  
  int count = 0;
  
  while(true) {
    if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) {
      task.notify_ext(1, NOTIFY_ACTION_INCREMENT, &count);
    }
    
    delay(20);
  }
}

static std::uint32_t notify_take(bool clear_on_exit, std::uint32_t timeout)

Waits for a notification to be nonzero.

Parameters
clear_on_exit If true (1), then the notification value is cleared. If false (0), then the notification value is decremented.
timeout Specifies the amount of time to be spent waiting for a notification to occur.
Returns The value of the task's notification value before it is decremented or cleared

See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for details.

Example

void my_task_fn(void* ign) {
  pros::Task task = pros::task::current();
  while(task.notify_take(true, TIMEOUT_MAX)) {
    puts("I was unblocked!");
  }
}

void opcontrol() {
  pros::Task task(my_task_fn);
  while(true) {
    if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) {
      task.notify(my_task);
    }
  }
}

bool notify_clear()

Clears the notification for a task.

Returns

False if there was not a notification waiting, true if there was Example

void my_task_fn(void* param) {
  pros::Task task = pros::Task::current();
  while(true) {
    printf("Waiting for notification...\n");
       printf("Got a notification: %d\n", task.notify_take(false, TIMEOUT_MAX));

       tasK_notify(task);
    delay(10):
  }
}

void opcontrol() {
  pros::Task task(my_task_fn);
  while(true) {
    if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) {
      task.notify();
    }
    delay(10);
  }
}

See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for details.

static void delay(const std::uint32_t milliseconds)

Delays the current task for a specified number of milliseconds.

Parameters
milliseconds The number of milliseconds to wait (1000 milliseconds per second)

This is not the best method to have a task execute code at predefined intervals, as the delay time is measured from when the delay is requested. To delay cyclically, use task_delay_until().

Example

void opcontrol() {
  while (true) {
    // Do opcontrol things
    pros::Task::delay(2);
  }

static void delay_until(std::uint32_t*const prev_time, const std::uint32_t delta)

Delays the current Task until a specified time.

Parameters
prev_time A pointer to the location storing the setpoint time. This should typically be initialized to the return value from pros::millis().
delta The number of milliseconds to wait (1000 milliseconds per second)

This function can be used by periodic tasks to ensure a constant execution frequency.

The task will be woken up at the time *prev_time + delta, and *prev_time will be updated to reflect the time at which the task will unblock.

Example

void opcontrol() {
  while (true) {
    // Do opcontrol things
    pros::Task::delay(2);
  }
}

static std::uint32_t get_count()

Gets the number of tasks the kernel is currently managing, including all ready, blocked, or suspended tasks.

Returns The number of tasks that are currently being managed by the kernel.

A task that has been deleted, but not yet reaped by the idle task will also be included in the count. Tasks recently created may take one context switch to be counted.

Example

void my_task_fn(void* param) {
  printf("Hello %s\n", (char*)param);
  // ...
}

void opcontrol() {
  pros::Task my_task(my_task_fn);
  printf("There are %d tasks running\n", pros::Task::get_count());
}

static time_point now()

Gets the current time.

Returns The current time

Effectively a wrapper around pros::millis()

Example

void opcontrol() {
  pros::Clock::time_point start = pros::Clock::now();
  pros::Clock::time_point end = pros::Clock::now();
  pros::Clock::duration duration = end - start;
  printf("Duration: %d\n", duration.count());

  if(duration.count() == 500) {
    // If you see this comment in the DOCS, ping @pros in VTOW. 
    // If you are the first person to do so, you will receive a free PROS 
       // holo!
    printf("Duration is 500 milliseconds\n");
  }
}

Mutex()

Mutex(const Mutex&) deleted

Mutex(Mutex&&) deleted

Mutex& operator=(const Mutex&) deleted

Mutex& operator=(Mutex&&) deleted

bool take()

Takes and locks a mutex indefinetly.

Returns True if the mutex was successfully taken, false otherwise. If false is returned, then errno is set with a hint about why the the mutex couldn't be taken

See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes for details.

Example

// Global variables for the robot's odometry, which the rest of the robot's
// subsystems will utilize
double odom_x = 0.0;
double odom_y = 0.0;
double odom_heading = 0.0;

// This mutex protects the odometry data. Whenever we read or write to the
// odometry data, we should make copies into the local variables, and read
// all 3 values at once to avoid errors.
pros::Mutex odom_mutex;

void odom_task(void* param) {
  while(true) {
    // First we fetch the odom coordinates from the previous iteration of the
    // odometry task. These are put into local variables so that we can
    // keep the size of the critical section as small as possible. This lets
    // other tasks that need to use the odometry data run until we need to
    // update it again.
    odom_mutex.take();
    double x_old = odom_x;
    double y_old = odom_y;
    double heading_old = odom_heading;
    odom_mutex.give();

    double x_new = 0.0;
    double y_new = 0.0;
    double heading_new = 0.0;
    
    // --- Calculate new pose for the robot here ---

    // Now that we have the new pose, we can update the global variables
    odom_mutex.take();
    odom_x = x_new;
    odom_y = y_new;
    odom_heading = heading_new;
    odom_mutex.give();
    
    delay(10);
  }
}

void chassis_task(void* param) {
  while(true) {
    // Here we copy the current odom values into local variables so that
    // we can use them without worrying about the odometry task changing say,
    // the y value right after we've read the x. This ensures our values are
    // sound.
    odom_mutex.take();
    double current_x = odom_x;
    double current_y = odom_y;
    double current_heading = odom_heading;
    odom_mutex.give();
    
    // ---- Move the robot using the current locations goes here ----
    
    delay(10);
  }
}

void initialize() {
  odom_mutex = pros::Mutex();

  pros::Task odom_task(odom_task, "Odometry Task");
  pros::Task chassis_task(odom_task, "Chassis Control Task");
}

.

bool take(std::uint32_t timeout)

Takes and locks a mutex, waiting for up to a certain number of milliseconds before timing out.

Parameters
timeout Time to wait before the mutex becomes available. A timeout of 0 can be used to poll the mutex. TIMEOUT_MAX can be used to block indefinitely.
Returns True if the mutex was successfully taken, false otherwise. If false is returned, then errno is set with a hint about why the the mutex couldn't be taken.

See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes for details.

Example

// Global variables for the robot's odometry, which the rest of the robot's
// subsystems will utilize
double odom_x = 0.0;
double odom_y = 0.0;
double odom_heading = 0.0;

// This mutex protects the odometry data. Whenever we read or write to the
// odometry data, we should make copies into the local variables, and read
// all 3 values at once to avoid errors.
pros::Mutex odom_mutex;

void odom_task(void* param) {
  while(true) {
    // First we fetch the odom coordinates from the previous iteration of the
    // odometry task. These are put into local variables so that we can
    // keep the size of the critical section as small as possible. This lets
    // other tasks that need to use the odometry data run until we need to
    // update it again.
    odom_mutex.take();
    double x_old = odom_x;
    double y_old = odom_y;
    double heading_old = odom_heading;
    odom_mutex.give();

    double x_new = 0.0;
    double y_new = 0.0;
    double heading_new = 0.0;
    
    // --- Calculate new pose for the robot here ---

    // Now that we have the new pose, we can update the global variables
    odom_mutex.take();
    odom_x = x_new;
    odom_y = y_new;
    odom_heading = heading_new;
    odom_mutex.give();
    
    delay(10);
  }
}

void chassis_task(void* param) {
  while(true) {
    // Here we copy the current odom values into local variables so that
    // we can use them without worrying about the odometry task changing say,
    // the y value right after we've read the x. This ensures our values are
    // sound.
    odom_mutex.take();
    double current_x = odom_x;
    double current_y = odom_y;
    double current_heading = odom_heading;
    odom_mutex.give();
    
    // ---- Move the robot using the current locations goes here ----
    
    delay(10);
  }
}

void initialize() {
  odom_mutex = pros::Mutex();

  pros::Task odom_task(odom_task, "Odometry Task");
  pros::Task chassis_task(odom_task, "Chassis Control Task");
}

.

bool give()

Unlocks a mutex.

Returns True if the mutex was successfully returned, false otherwise. If false is returned, then errno is set with a hint about why the mutex couldn't be returned.

See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes for details.

Example

// Global variables for the robot's odometry, which the rest of the robot's
// subsystems will utilize
double odom_x = 0.0;
double odom_y = 0.0;
double odom_heading = 0.0;

// This mutex protects the odometry data. Whenever we read or write to the
// odometry data, we should make copies into the local variables, and read
// all 3 values at once to avoid errors.
pros::Mutex odom_mutex;

void odom_task(void* param) {
  while(true) {
    // First we fetch the odom coordinates from the previous iteration of the
    // odometry task. These are put into local variables so that we can
    // keep the size of the critical section as small as possible. This lets
    // other tasks that need to use the odometry data run until we need to
    // update it again.
    odom_mutex.take();
    double x_old = odom_x;
    double y_old = odom_y;
    double heading_old = odom_heading;
    odom_mutex.give();

    double x_new = 0.0;
    double y_new = 0.0;
    double heading_new = 0.0;
    
    // --- Calculate new pose for the robot here ---

    // Now that we have the new pose, we can update the global variables
    odom_mutex.take();
    odom_x = x_new;
    odom_y = y_new;
    odom_heading = heading_new;
    odom_mutex.give();
    
    delay(10);
  }
}

void chassis_task(void* param) {
  while(true) {
    // Here we copy the current odom values into local variables so that
    // we can use them without worrying about the odometry task changing say,
    // the y value right after we've read the x. This ensures our values are
    // sound.
    odom_mutex.take();
    double current_x = odom_x;
    double current_y = odom_y;
    double current_heading = odom_heading;
    odom_mutex.give();
    
    // ---- Move the robot using the current locations goes here ----
    
    delay(10);
  }
}

void initialize() {
  odom_mutex = pros::Mutex();

  pros::Task odom_task(odom_task, "Odometry Task");
  pros::Task chassis_task(odom_task, "Chassis Control Task");
}

.

void lock()

Takes and locks a mutex, waiting for up to TIMEOUT_MAX milliseconds.

Exceptions
std::system_error Mutex could not be locked within TIMEOUT_MAX milliseconds. see errno for details.

Effectively equivalent to calling pros::Mutex::take with TIMEOUT_MAX as the parameter.

Conforms to named requirment BasicLockable

Example

// Global variables for the robot's odometry, which the rest of the robot's
// subsystems will utilize
double odom_x = 0.0;
double odom_y = 0.0;
double odom_heading = 0.0;

// This mutex protects the odometry data. Whenever we read or write to the
// odometry data, we should make copies into the local variables, and read
// all 3 values at once to avoid errors.
pros::Mutex odom_mutex;

void odom_task(void* param) {
  while(true) {
    // First we fetch the odom coordinates from the previous iteration of the
    // odometry task. These are put into local variables so that we can
    // keep the size of the critical section as small as possible. This lets
    // other tasks that need to use the odometry data run until we need to
    // update it again.
    odom_mutex.lock();
    double x_old = odom_x;
    double y_old = odom_y;
    double heading_old = odom_heading;
    odom_mutex.unlock();

    double x_new = 0.0;
    double y_new = 0.0;
    double heading_new = 0.0;
    
    // --- Calculate new pose for the robot here ---

    // Now that we have the new pose, we can update the global variables
    odom_mutex.lock();
    odom_x = x_new;
    odom_y = y_new;
    odom_heading = heading_new;
    odom_mutex.unlock();
    
    delay(10);
  }
}

void chassis_task(void* param) {
  while(true) {
    // Here we copy the current odom values into local variables so that
    // we can use them without worrying about the odometry task changing say,
    // the y value right after we've read the x. This ensures our values are
    // sound.
    odom_mutex.lock();
    double current_x = odom_x;
    double current_y = odom_y;
    double current_heading = odom_heading;
    odom_mutex.unlock();
    
    // ---- Move the robot using the current locations goes here ----
    
    delay(10);
  }
}

void initialize() {
  odom_mutex = pros::Mutex();

  pros::Task odom_task(odom_task, "Odometry Task");
  pros::Task chassis_task(odom_task, "Chassis Control Task");
}

.

void unlock()

Unlocks a mutex.

Equivalent to calling pros::Mutex::give.

Conforms to named requirement BasicLockable

Example

// Global variables for the robot's odometry, which the rest of the robot's
// subsystems will utilize
double odom_x = 0.0;
double odom_y = 0.0;
double odom_heading = 0.0;

// This mutex protects the odometry data. Whenever we read or write to the
// odometry data, we should make copies into the local variables, and read
// all 3 values at once to avoid errors.
pros::Mutex odom_mutex;

void odom_task(void* param) {
  while(true) {
    // First we fetch the odom coordinates from the previous iteration of the
    // odometry task. These are put into local variables so that we can
    // keep the size of the critical section as small as possible. This lets
    // other tasks that need to use the odometry data run until we need to
    // update it again.
    odom_mutex.lock();
    double x_old = odom_x;
    double y_old = odom_y;
    double heading_old = odom_heading;
    odom_mutex.unlock();

    double x_new = 0.0;
    double y_new = 0.0;
    double heading_new = 0.0;
    
    // --- Calculate new pose for the robot here ---

    // Now that we have the new pose, we can update the global variables
    odom_mutex.lock();
    odom_x = x_new;
    odom_y = y_new;
    odom_heading = heading_new;
    odom_mutex.unlock();
    
    delay(10);
  }
}

void chassis_task(void* param) {
  while(true) {
    // Here we copy the current odom values into local variables so that
    // we can use them without worrying about the odometry task changing say,
    // the y value right after we've read the x. This ensures our values are
    // sound.
    odom_mutex.lock();
    double current_x = odom_x;
    double current_y = odom_y;
    double current_heading = odom_heading;
    odom_mutex.unlock();
    
    // ---- Move the robot using the current locations goes here ----
    
    delay(10);
  }
}

void initialize() {
  odom_mutex = pros::Mutex();

  pros::Task odom_task(odom_task, "Odometry Task");
  pros::Task chassis_task(odom_task, "Chassis Control Task");
}

.

bool try_lock()

Try to lock a mutex.

Returns True when lock was acquired succesfully, or false otherwise.

Returns immediately if unsucessful.

Conforms to named requirement Lockable

pros::Mutex mutex;

void my_task_fn(void* param) { while (true) { if(mutex.try_lock()) { printf("Mutex aquired successfully!\n"); // Do stuff that requires the protected resource here } else { printf("Mutex not aquired!\n"); } } }

template<typename Rep, typename Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& rel_time)

Takes and locks a mutex, waiting for a specified duration.

Parameters
rel_time Time to wait before the mutex becomes available.
Returns True if the lock was acquired succesfully, otherwise false.

Equivalent to calling pros::Mutex::take with a duration specified in milliseconds.

Conforms to named requirement TimedLockable

Example

void my_task_fn(void* param) {
  while (true) {
    if(mutex.try_lock_for(std::chrono::milliseconds(100))) {
      printf("Mutex aquired successfully!\n");
      // Do stuff that requires the protected resource here
    }
    else {
      printf("Mutex not aquired after 100 milliseconds!\n");
    }
  }
}

template<typename Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& abs_time)

Takes and locks a mutex, waiting until a specified time.

Parameters
abs_time Time point until which to wait for the mutex.
Returns True if the lock was acquired succesfully, otherwise false.

Conforms to named requirement TimedLockable

Example

void my_task_fn(void* param) {
  while (true) {
    // Get the current time point
    auto now = std::chrono::system_clock::now();

    // Calculate the time point 100 milliseconds from now
    auto abs_time = now + std::chrono::milliseconds(100);

    if(mutex.try_lock_until(abs_time)) {
      printf("Mutex aquired successfully!\n");
      // Do stuff that requires the protected resource here
    }
    else {
      printf("Mutex not aquired after 100 milliseconds!\n");
    }
  }
}

Typedef documentation

using rep = std::uint32_t

using period = std::milli

using duration = std::chrono::duration<rep, period>

using time_point = std::chrono::time_point<Clock>

Variable documentation

const bool is_steady

std::shared_ptr<std::remove_pointer_t<mutex_t>> mutex