Saturday, November 16, 2024
Google search engine
HomeGuest BlogsPeterson’s Algorithm for Mutual Exclusion | Set 1 (Basic C implementation)

Peterson’s Algorithm for Mutual Exclusion | Set 1 (Basic C implementation)

Problem: Given 2 processes i and j, you need to write a program that can guarantee mutual exclusion between the two without any additional hardware support.

Solution: There can be multiple ways to solve this problem, but most of them require additional hardware support. The simplest and the most popular way to do this is by using Peterson’s Algorithm for mutual Exclusion. It was developed by Peterson in 1981 though the initial work in this direction was done by Theodorus Jozef Dekker who came up with Dekker’s algorithm in 1960, which was later refined by Peterson and came to be known as Peterson’s Algorithm.

Basically, Peterson’s algorithm provides guaranteed mutual exclusion by using only the shared memory. It uses two ideas in the algorithm:

  1. Willingness to acquire lock.
  2. Turn to acquire lock.

Prerequisite: Multithreading in C

Explanation:

The idea is that first a thread expresses its desire to acquire a lock and sets flag[self] = 1 and then gives the other thread a chance to acquire the lock. If the thread desires to acquire the lock, then, it gets the lock and passes the chance to the 1st thread. If it does not desire to get the lock then the while loop breaks and the 1st thread gets the chance.

Implementation:

C++

// Filename: peterson_spinlock.cpp
// Use below command to compile:
// g++ -pthread peterson_spinlock.cpp -o peterson_spinlock

#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

int flag[2];
int turn;
const int MAX = 1e9;
int ans = 0;

void lock_init()
{
    flag[0] = flag[1] = 0;
    turn = 0;
}

void lock(int self)
{
    flag[self] = 1;
    turn = 1 - self;

    while (flag[1 - self] == 1 && turn == 1 - self);
}

void unlock(int self)
{
    flag[self] = 0;
}

void func(int self)
{
    int i = 0;
    cout << "Thread Entered: " << self << endl;

    lock(self);

    for (i = 0; i < MAX; i++)
        ans++;

    unlock(self);
}

int main()
{
    thread t1(func, 0);
    thread t2(func, 1);

    lock_init();

    t1.join();
    t2.join();

    cout << "Actual Count: " << ans << " | Expected Count: " << MAX * 2 << endl;

    return 0;
}
// Note :  To compile your code correctly, you need to link it with the pthread library.
//g++ -pthread peterson_spinlock.cpp -o peterson_spinlock

C

// Filename: peterson_spinlock.c
// Use below command to compile:
// gcc -pthread peterson_spinlock.c -o peterson_spinlock

#include <stdio.h>
#include <pthread.h>
#include"mythreads.h"

int flag[2];
int turn;
const int MAX = 1e9;
int ans = 0;

void lock_init()
{
    // Initialize lock by resetting the desire of
    // both the threads to acquire the locks.
    // And, giving turn to one of them.
    flag[0] = flag[1] = 0;
    turn = 0;
}

// Executed before entering critical section
void lock(int self)
{
    // Set flag[self] = 1 saying you want to acquire lock
    flag[self] = 1;

    // But, first give the other thread the chance to
    // acquire lock
    turn = 1-self;

    // Wait until the other thread looses the desire
    // to acquire lock or it is your turn to get the lock.
    while (flag[1-self]==1 && turn==1-self) ;
}

// Executed after leaving critical section
void unlock(int self)
{
    // You do not desire to acquire lock in future.
    // This will allow the other thread to acquire
    // the lock.
    flag[self] = 0;
}

// A Sample function run by two threads created 
// in main()
void* func(void *s)
{
    int i = 0;
    int self = (int *)s;
    printf("Thread Entered: %d\n", self);

    lock(self);

    // Critical section (Only one thread
    // can enter here at a time)
    for (i=0; i<MAX; i++)
        ans++;

    unlock(self);
}

// Driver code
int main()
{
    // Initialized the lock then fork 2 threads
    pthread_t p1, p2;
    lock_init();

    // Create two threads (both run func) 
    pthread_create(&p1, NULL, func, (void*)0);
    pthread_create(&p2, NULL, func, (void*)1);

    // Wait for the threads to end.
    pthread_join(p1, NULL);
    pthread_join(p2, NULL);

    printf("Actual Count: %d | Expected Count: %d\n",
                                        ans, MAX*2);

    return 0;
}

Java

// Filename: peterson_spinlock.cpp
// Use below command to compile:
// g++ -pthread peterson_spinlock.cpp -o peterson_spinlock

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PetersonSpinlockMain {
    // Shared variables for mutual exclusion
    private static int[] flag = new int[2];
    private static int turn;
    private static final int MAX = (int) 1e9;
    private static int ans = 0;
    private static Lock mutex = new ReentrantLock();

    // Initialize lock variables
    private static void lockInit() {
        flag[0] = flag[1] = 0;
        turn = 0;
    }

    // Acquire lock
    private static void lock(int self) {
        flag[self] = 1;
        turn = 1 - self;

        // Spin until the other thread releases the lock
        while (flag[1 - self] == 1 && turn == 1 - self);
    }

    // Release lock
    private static void unlock(int self) {
        flag[self] = 0;
    }

    // Function representing the critical section
    private static void func(int self) {
        int i;
        System.out.println("Thread Entered: " + self);

        lock(self); // Acquire the lock

        for (i = 0; i < MAX; i++)
            ans++;

        unlock(self); // Release the lock
    }

    // Main method
    public static void main(String[] args) throws InterruptedException {
        // Create two threads
        Thread t1 = new Thread(() -> func(0));
        Thread t2 = new Thread(() -> func(1));

        lockInit(); // Initialize lock variables

        t1.start(); // Start thread 1
        t2.start(); // Start thread 2

        t1.join(); // Wait for thread 1 to finish
        t2.join(); // Wait for thread 2 to finish

        // Print the final count
        System.out.println("Actual Count: " + ans + " | Expected Count: " + MAX * 2);
    }
}
// This code is contributed by utkarsh

Python

import threading

flag = [0, 0]
turn = 0
MAX = 100000  # Reduced value
ans = 0

def lock_init():
    global flag, turn
    flag = [0, 0]
    turn = 0

def lock(self):
    global flag, turn
    flag[self] = 1
    turn = 1 - self

    while flag[1 - self] == 1 and turn == 1 - self:
        pass

def unlock(self):
    global flag
    flag[self] = 0

def func(self):
    global ans
    i = 0
    print("Thread Entered:", self)

    lock(self)

    for i in range(MAX):
        ans += 1

    unlock(self)

def main():
    t1 = threading.Thread(target=func, args=(0,))
    t2 = threading.Thread(target=func, args=(1,))

    lock_init()

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print("Actual Count:", ans, "| Expected Count:", MAX * 2)

if __name__ == "__main__":
    main()

C#

using System;
using System.Threading;

class Program
{
    const int MAX = 1000000000; // Maximum count
    static int ans = 0; // Shared variable to be incremented in the critical section

    // Function representing the work to be done in each thread
    static void Func(object obj)
    {
        int self = (int)obj; // Convert object to integer representing the thread index
        Console.WriteLine("Thread Entered: " + self); // Print thread entry message

        // Perform some work (incrementing a counter)
        for (int i = 0; i < MAX; i++)
        {
            lock (typeof(Program)) // Acquire lock to ensure mutual exclusion
            {
                ans++;
            }
        }
    }

    static void Main(string[] args)
    {
        Thread t1 = new Thread(Func); // Create thread 1
        Thread t2 = new Thread(Func); // Create thread 2

        t1.Start(0); // Start thread 1
        t2.Start(1); // Start thread 2

        t1.Join(); // Wait for thread 1 to finish
        t2.Join(); // Wait for thread 2 to finish

        // Print actual count and expected count
        Console.WriteLine("Actual Count: " + ans + " | Expected Count: " + (MAX * 2));
    }
}

JavaScript

const flag = [0, 0];
let turn = 0;
const MAX = 1e9;
let ans = 0;

function lock_init() {
    flag[0] = flag[1] = 0;
    turn = 0;
}

function lock(self) {
    flag[self] = 1;
    turn = 1 - self;

    while (flag[1 - self] === 1 && turn === 1 - self);
}

function unlock(self) {
    flag[self] = 0;
}

async function func(self) {
    let i = 0;
    console.log("Thread Entered:", self);

    lock(self);

    for (i = 0; i < MAX; i++)
        ans++;

    unlock(self);
}

async function main() {
    lock_init();

    const promise1 = func(0);
    const promise2 = func(1);

    await Promise.all([promise1, promise2]);

    console.log("Actual Count:", ans, "| Expected Count:", MAX * 2);
}

main();
//This code is contributed by Prachi

C++

#include <iostream>
#include <pthread.h>

using namespace std;

int flag[2];
int turn;
const int MAX = 1e9;
int ans = 0;

void lock_init()
{
    flag[0] = flag[1] = 0;
    turn = 0;
}

void lock(int self)
{
    flag[self] = 1;
    turn = 1 - self;

    while (flag[1 - self] == 1 && turn == 1 - self);
}

void unlock(int self)
{
    flag[self] = 0;
}

void* func(void* s)
{
    int i = 0;
    int self = (int)s;
    cout << "Thread Entered: " << self << endl;

    lock(self);

    for (i = 0; i < MAX; i++)
        ans++;

    unlock(self);

    return nullptr;
}

int main()
{
    pthread_t p1, p2;

    lock_init();

    pthread_create(&p1, nullptr, func, (void*)0);
    pthread_create(&p2, nullptr, func, (void*)1);

    pthread_join(p1, nullptr);
    pthread_join(p2, nullptr);

    cout << "Actual Count: " << ans << " | Expected Count: " << MAX * 2 << endl;

    return 0;

C

// mythread.h (A wrapper header file with assert
// statements)
#ifndef __MYTHREADS_h__
#define __MYTHREADS_h__

#include <pthread.h>
#include <assert.h>
#include <sched.h>

void Pthread_mutex_lock(pthread_mutex_t *m)
{
    int rc = pthread_mutex_lock(m);
    assert(rc == 0);
}
                                                                                
void Pthread_mutex_unlock(pthread_mutex_t *m)
{
    int rc = pthread_mutex_unlock(m);
    assert(rc == 0);
}
                                                                                
void Pthread_create(pthread_t *thread, const pthread_attr_t *attr,     
           void *(*start_routine)(void*), void *arg)
{
    int rc = pthread_create(thread, attr, start_routine, arg);
    assert(rc == 0);
}

void Pthread_join(pthread_t thread, void **value_ptr)
{
    int rc = pthread_join(thread, value_ptr);
    assert(rc == 0);
}

#endif // __MYTHREADS_h__

Java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PetersonSpinlockThread {
    // Shared variables for mutual exclusion
    private static int[] flag = new int[2];
    private static int turn;
    private static final int MAX = (int) 1e9;
    private static int ans = 0;
    private static Lock mutex = new ReentrantLock();

    // Initialize lock variables
    private static void lockInit() {
        flag[0] = flag[1] = 0;
        turn = 0;
    }

    // Acquire lock
    private static void lock(int self) {
        flag[self] = 1;
        turn = 1 - self;

        // Spin until the other thread releases the lock
        while (flag[1 - self] == 1 && turn == 1 - self);
    }

    // Release lock
    private static void unlock(int self) {
        flag[self] = 0;
    }

    // Function representing the critical section
    private static void func(int self) {
        int i = 0;
        System.out.println("Thread Entered: " + self);

        lock(self); // Acquire the lock

        for (i = 0; i < MAX; i++)
            ans++;

        unlock(self); // Release the lock
    }

    // Main method
    public static void main(String[] args) throws InterruptedException {
        // Create two threads
        Thread t1 = new Thread(() -> func(0));
        Thread t2 = new Thread(() -> func(1));

        lockInit(); // Initialize lock variables

        t1.start(); // Start thread 1
        t2.start(); // Start thread 2

        t1.join(); // Wait for thread 1 to finish
        t2.join(); // Wait for thread 2 to finish

        // Print the final count
        System.out.println("Actual Count: " + ans + " | Expected Count: " + MAX * 2);
    }
}

JavaScript

const flag = [0, 0];
let turn = 0;
const MAX = 1e9;
let ans = 0;

function lock_init() {
    flag[0] = flag[1] = 0;
    turn = 0;
}

function lock(self) {
    flag[self] = 1;
    turn = 1 - self;

    while (flag[1 - self] === 1 && turn === 1 - self);
}

function unlock(self) {
    flag[self] = 0;
}

async function func(self) {
    let i = 0;
    console.log("Thread Entered:", self);

    lock(self);

    for (i = 0; i < MAX; i++)
        ans++;

    unlock(self);
}

async function main() {
    lock_init();

    const promise1 = func(0);
    const promise2 = func(1);

    await Promise.all([promise1, promise2]);

    console.log("Actual Count:", ans, "| Expected Count:", MAX * 2);
}

main();
//This code is contribuited by Prachi.

Python3

import threading

# Shared variables for mutual exclusion
flag = [0, 0]
turn = 0
MAX = int(1e9)
ans = 0
mutex = threading.Lock()

# Initialize lock variables
def lock_init():
    global flag, turn
    flag = [0, 0]
    turn = 0

# Acquire lock
def lock(self):
    global flag, turn
    flag[self] = 1
    turn = 1 - self
    # Spin until the other thread releases the lock
    while flag[1 - self] == 1 and turn == 1 - self:
        pass

# Release lock
def unlock(self):
    global flag
    flag[self] = 0

# Function representing the critical section
def func(self):
    global ans
    i = 0
    print(f"Thread Entered: {self}")
    with mutex:
        lock(self)  # Acquire the lock
        for i in range(MAX):
            ans += 1
        unlock(self)  # Release the lock

# Main method
def main():
    # Create two threads
    t1 = threading.Thread(target=lambda: func(0))
    t2 = threading.Thread(target=lambda: func(1))
    lock_init()  # Initialize lock variables
    t1.start()  # Start thread 1
    t2.start()  # Start thread 2
    t1.join()  # Wait for thread 1 to finish
    t2.join()  # Wait for thread 2 to finish
    # Print the final count
    print(f"Actual Count: {ans} | Expected Count: {MAX * 2}")

if __name__ == "__main__":
    main()

Output: 

Thread Entered: 1
Thread Entered: 0
Actual Count: 2000000000 | Expected Count: 2000000000

The produced output is 2*109 where 109 is incremented by both threads.

If you like neveropen and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the neveropen main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
 

Last Updated :
18 Mar, 2024
Like Article
Save Article


Previous

<!–

8 Min Read | Java

–>


Next


<!–

8 Min Read | Java

–>

Share your thoughts in the comments

RELATED ARTICLES

Most Popular

Recent Comments