Peterson’s Algorithm on the Raspberry Pi Pico

When the Raspberry Pi Pico runs with two cores, vital resources must be protected by semaphores (Mutual Exclusion). This examples uses Peterson’s algorithm, which is rather simple for two threads / cores.

Note: The semaphore variables and the housekeeping variables are set up as ‘volatile’. This turned out to be necessary for the code to work.

References:
[1] https://wiki2.org/en/Peterson%27s_algorithm
[2] https://stackoverflow.com/questions/3896952/testing-a-semaphore-by-counting/a>

/*
 * Implementation of Peterson's Algorithm
 * See:  https://wiki2.org/en/Peterson%27s_algorithm
 */

/*
 *  Semaphore variables
 */
volatile uint8_t flags[2] = {false, false};
volatile uint8_t turn = 0;

/*
 * Housekeeping variables
 */
volatile uint8_t core0 = 0;
volatile uint8_t core1 = 0;
long errors = 0L;

/*
 * Test variable
 */
volatile long shared = 0L;

void inc() {
    shared++;
}

void dec() {
    shared--;
}

void setup() {
    uint8_t i;

    Serial.begin(9600);
    while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
    }
}

void setup1() {
    delay(1);
}

void loop() {
    long i;

    Serial.println( "Starting Peterson test loop ..." );

    for (i = 0L; i < 10000000L; i++) {
        flags[0] = true;
        turn = 1;

        while( (flags[1] == true) && (turn == 1) ) {
            // busy wait
            ;
        }

        /* Critical Section Code of the Process */

        // prevent compiler from doing optimizations
        inc();
        dec();

        /* End of Critical Section */
        flags[0] = false;

        //Serial.print( "." );
    }

    // wait until core 1 is finished
    while (core1 != 1) {
        Serial.println("Waiting for core 1 to finish ...");
        delay(100);
    }

    if (core1 == 1) {
        Serial.println("core 1 finished!");
        delay(1000);
    }

    if (shared != 0L) {
        errors++;
    }

    Serial.print( "shared = " );
    Serial.print( shared );
    Serial.print( " (errors  = " );
    Serial.print( errors );
    Serial.println( ")" );/*
 * Implementation of the Peterson's Algorithm
 * See:  https://wiki2.org/en/Peterson%27s_algorithm
 */

/*
 *  Semaphore variables
 */
volatile uint8_t flags[2] = {false, false};
volatile uint8_t turn = 0;

/*
 * Housekeeping variables
 */
volatile uint8_t core0 = 0;
volatile uint8_t core1 = 0;
long errors = 0L;

/*
 * Test variable
 */
volatile long shared = 0L;

void inc() {
    shared++;
}

void dec() {
    shared--;
}

void setup() {
    uint8_t i;

    Serial.begin(9600);
    while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
    }
}

void setup1() {
    delay(1);
}

void loop() {
    long i;

    Serial.println( "Starting Peterson test loop ..." );

    for (i = 0L; i < 10000000L; i++) {
        flags[0] = true;
        turn = 1;

        while( (flags[1] == true) && (turn == 1) ) {
            // busy wait
            ;
        }

        /* Critical Section Code of the Process */

        // prevent compiler from doing optimizations
        inc();
        dec();

        /* End of Critical Section */
        flags[0] = false;

        //Serial.print( "." );
    }

    // wait until core 1 is finished
    while (core1 != 1) {
        Serial.println("Waiting for core 1 to finish ...");
        delay(100);
    }

    if (core1 == 1) {
        Serial.println("core 1 finished!");
        delay(1000);
    }

    if (shared != 0L) {
        errors++;
    }

    Serial.print( "shared = " );
    Serial.print( shared );
    Serial.print( " (errors  = " );
    Serial.print( errors );
    Serial.println( ")" );

    // start all over
    shared = 0L;
    // indicate core 0 has finished the main loop and check
    core0 = 1;
    delay(1000);
    core0 = 0;
}


void loop1() {
    long i;

    for (i = 0L; i < 10000000L; i++) {
        flags[1] = true;
        turn = 0;

        while( (flags[0] == true) && (turn == 0) ) {
            // busy wait
            ;
        }

        /* Critical Section Code of the Process */

        // prevent compiler from doing optimizations
        inc();
        dec();

        /* End of Critical Section */
        flags[1] = false;
    }

    // indicate core 1 has finished the main loop
    core1 = 1;

    // wait until core 0 has finished the main loop plus check
    while (core0 != 1) {
        delay(1);
    }

    // start all over
    core1 = 0;
}


    // start all over
    shared = 0L;
    // indicate core 0 has finished the main loop and check
    core0 = 1;
    delay(1000);
    core0 = 0;
}


void loop1() {
    long i;

    for (i = 0L; i < 10000000L; i++) {
        flags[1] = true;
        turn = 0;

        while( (flags[0] == true) && (turn == 0) ) {
            // busy wait
            ;
        }

        /* Critical Section Code of the Process */

        // prevent compiler from doing optimizations
        inc();
        dec();

        /* End of Critical Section */
        flags[1] = false;
    }

    // indicate core 1 has finished the main loop
    core1 = 1;

    // wait until core 0 has finished the main loop plus check
    while (core0 != 1) {
        delay(1);
    }

    // start all over
    core1 = 0;
}