Open In App

Non-Repeating Elements of a given array using Multithreaded program

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] of size N and an integer T representing the count of threads, the task is to find all non-repeating array elements using multithreading.

Examples:

Input: arr[] = { 1, 0, 5, 5, 2}, T = 3 
Output: 0 1 2 
Explanation: 
The frequency of 0 in the array arr[] is 1. 
The frequency of 1 in the array arr[] is 1. 
The frequency of 2 in the array arr[] is 1. 
Therefore, the required output is 0 1 2

Input: arr[] = { 1, 1, 5, 5, 2, 4 }, T = 3 
Output: 2 4 
Explanation: 
The frequency of 2 in the array arr[] is 1. 
The frequency of 4 in the array arr[] is 1. 
Therefore, the required output is 2 4

Approach: The idea is to use the pthread library available in C++ to create multiple threads for concurrent process flow and perform multiple operations( pthread create, pthread join , lock, etc) in multithreaded program. Follow the steps below to solve the problem:

  • Divide the array into T subarrays, such that each subarray of size N / T will be executed in a single thread.
  • Initialize a Map, say mp, to store the frequencies of each array element.
  • Create a pthread_mutex_lock, say lock1, to ensure that all threads do not trip over each other and corrupt the Map container.
  • Define a function func() for executing the body of a thread. This function is often called the kernel of the thread and is provided during thread creation.
    • Lock the current thread using pthread_mutex_lock() so that it does not overlap with other threads
    • Traverse through the given range as an argument to the function func() in the array arr[] and increment the frequency of the array element which is encountered.
    • Release the current thread using the function pthread_mutex_unlock().
  • Initialize an array, say thread[], of type pthread_t for storing the threads.
  • Iterate over the range [0, T] and create a thread by calling pthread_create() function and store it in the thread[i]
  • While each thread performs their individual tasks, the main() function will need to wait till each of the threads finish their work. 
    • Use pthread_join() function for waiting till each thread finishes executing function func()
    • Iterate over the range [0, T] and call pthread_create() function for each thread[i]
  • Finally, traverse the map mp and print the element occurring only once.

Below is the implementation of the above approach:

C++




// C++ program to implement
// the above approach
 
#include <bits/stdc++.h>
#include <pthread.h>
using namespace std;
 
// Structure of subarray
// of the array
struct range_info {
 
    // Stores start index
    // of the subarray
    int start;
 
    // Stores end index
    // of the subarray
    int end;
 
    // Stores pointer to the
    // first array element
    int* a;
};
 
 
// Declaring map, and mutex for
// thread exclusion(lock)
map<int, int> mp;
pthread_mutex_t lock1;
 
 
// Function performed by every thread to
// count the frequency of array elements
// in current subarray
void* func(void* arg)
{
    // Taking a lock so that threads
    // do not overlap each other
    pthread_mutex_lock(&lock1);
     
     
    // Initialize range_info
    // for each thread
    struct range_info* rptr
    = (struct range_info*)arg;
 
 
    // Thread is going through the array
    // to check and update the map
    for (int i = rptr->start;
            i <= rptr->end; i++) {
                     
         
        // Stores iterator to the map        
        map<int, int>::iterator it;
         
         
        // Update it
        it = mp.find(rptr->a[i]);
         
         
        // If rptr->a[i] not found
        // in map mp
        if (it == mp.end()) {
             
             
            // Insert rptr->a[i] with
            // frequency 1
            mp.insert({ rptr->a[i], 1 });
        }
        else {
             
             
            // Update frequency of
            // current element
            it->second++;
        }
    }
     
 
    // Thread releases the lock
    pthread_mutex_unlock(&lock1);
    return NULL;
}
 
 
// Function to find the unique
// numbers in the array
void numbers_occuring_once(int arr[],
                        int N, int T)
{
    // Stores all threads
    pthread_t threads[T];
 
    // Stores start index of
    // first thread
    int spos = 0;
 
    // Stores last index
    // of the first thread
    int epos = spos + (N / T) - 1;
 
    // Traverse each thread
    for (int i = 0; i < T; i++) {
 
        // Initialize range_info for
        // current thread
        struct range_info* rptr
            = (struct range_info*)malloc(
                sizeof(struct range_info));
 
        // Update start index of
        // current subarray    
        rptr->start = spos;
 
        // Stores end index of
        // current subarray
        rptr->end = epos;
 
        // Update pointer to the first
        // element of the array
        rptr->a = arr;
         
         
        // creating each thread with
        // appropriate parameters
        int a
        = pthread_create(&threads[i], NULL,
                        func, (void*)(rptr));
                         
                         
        // updating the parameters
        // for the next thread
        spos = epos + 1;
        epos = spos + (N / T) - 1;
        if (i == T - 2) {
            epos = N - 1;
        }
    }
 
    // Waiting for threads to finish
    for (int i = 0; i < T; i++) {
        int rc
        = pthread_join(threads[i], NULL);
    }
 
    // Traverse the map
    for (auto it: mp) {
                 
                 
                                     
    // If frequency of current
    // element is 1                            
        if (it.second == 1) {
 
            // Print the element
            cout << it.first << " ";
        }
    }
}
 
 
// Drivers Code
int main()
{
    // initializing the mutex lock
    pthread_mutex_init(&lock1, NULL);
    int T = 3;
    int arr[] = { 1, 0, 5, 5, 2, 6 };
    int N = sizeof(arr) / sizeof(arr[0]);
    numbers_occuring_once(arr, N, T);
}


Java




import java.util.HashMap;
import java.util.Map;
 
public class Main {
 
  // Structure of subarray of the array
  static class RangeInfo {
 
    // Stores start index of the subarray
    int start;
 
    // Stores end index of the subarray
    int end;
 
    // Stores pointer to the first array element
    int[] a;
 
    RangeInfo(int start, int end, int[] a)
    {
      this.start = start;
      this.end = end;
      this.a = a;
    }
  }
 
  // Declaring map for thread exclusion(lock)
  static Map<Integer, Integer> mp = new HashMap<>();
 
  // Function performed by every thread to
  // count the frequency of array elements
  // in current subarray
  static void func(RangeInfo rptr)
  {
    // Initialize range_info for each thread
 
    // Thread is going through the array
    // to check and update the map
    for (int i = rptr.start; i <= rptr.end; i++) {
 
      // Stores value of the current element
      int curr = rptr.a[i];
 
      // Synchronize access to the map
      synchronized (mp)
      {
        // Stores the frequency of the current
        // element
        Integer freq = mp.get(curr);
 
        // If curr not found in map mp
        if (freq == null) {
          // Insert curr with frequency 1
          mp.put(curr, 1);
        }
        else {
          // Update frequency of current element
          mp.put(curr, freq + 1);
        }
      }
    }
  }
 
  // Function to find the unique numbers in the array
  static void numbersOccurringOnce(int[] arr, int n,
                                   int t)
  {
    // Stores all threads
    Thread[] threads = new Thread[t];
 
    // Stores start index of first thread
    final int spos = 0;
 
    // Stores last index of the first thread
    final int epos = spos + (n / t) - 1;
 
    // Traverse each thread
    for (int i = 0; i < t; i++) {
 
      // Update start index of current subarray
      final int start = spos + (n / t) * i;
 
      // Stores end index of current subarray
      final int end
        = i == t - 1 ? n - 1
        : spos + (n / t) * (i + 1) - 1;
 
      // Initialize range_info for current thread
      RangeInfo rptr = new RangeInfo(start, end, arr);
 
      // creating each thread with appropriate
      // parameters
      threads[i] = new Thread(() -> func(rptr));
    }
 
    // Starting all threads
    for (int i = 0; i < t; i++) {
      threads[i].start();
    }
 
    // Waiting for threads to finish
    for (int i = 0; i < t; i++) {
      try {
        threads[i].join();
      }
      catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
 
    // Traverse the map
    for (Map.Entry<Integer, Integer> it :
         mp.entrySet()) {
      // If frequency of current element is 1
      if (it.getValue() == 1) {
        // Print the element
        System.out.print(it.getKey() + " ");
      }
    }
  }
 
  // Driver's Code
  public static void main(String[] args)
    throws InterruptedException
  {
    // initializing the mutex lock
    Object lock1 = new Object();
 
    int T = 3;
    int[] arr = { 1, 0, 5, 5, 2, 6 };
    int N = arr.length;
    numbersOccurringOnce(arr, N, T);
  }
}


Python3




import threading
 
# Structure of subarray of the array
class RangeInfo:
    # Stores start index of the subarray
    def __init__(self, start, end, a):
        self.start = start
        self.end = end
        self.a = a
 
# Declaring map for thread exclusion(lock)
mp = {}
 
# Function performed by every thread to
# count the frequency of array elements
# in current subarray
def func(rptr):
    # Thread is going through the array
    # to check and update the map
    for i in range(rptr.start, rptr.end + 1):
        # Stores value of the current element
        curr = rptr.a[i]
 
        # Synchronize access to the map
        with threading.Lock():
            # Stores the frequency of the current
            # element
            freq = mp.get(curr, 0)
 
            # If curr not found in map mp
            if freq == 0:
                # Insert curr with frequency 1
                mp[curr] = 1
            else:
                # Update frequency of current element
                mp[curr] = freq + 1
 
# Function to find the unique numbers in the array
def numbersOccurringOnce(arr, n, t):
    # Stores all threads
    threads = []
 
    # Stores start index of first thread
    spos = 0
 
    # Stores last index of the first thread
    epos = spos + (n // t) - 1
 
    # Traverse each thread
    for i in range(t):
        # Update start index of current subarray
        start = spos + (n // t) * i
 
        # Stores end index of current subarray
        end = n - 1 if i == t - 1 else spos + (n // t) * (i + 1) - 1
 
        # Initialize range_info for current thread
        rptr = RangeInfo(start, end, arr)
 
        # creating each thread with appropriate
        # parameters
        threads.append(threading.Thread(target=func, args=(rptr,)))
 
    # Starting all threads
    for thread in threads:
        thread.start()
 
    # Waiting for threads to finish
    for thread in threads:
        thread.join()
 
    # Traverse the map
    for key, value in mp.items():
        # If frequency of current element is 1
        if value == 1:
            # Print the element
            print(key, end=" ")
 
# Drivers Code
if __name__ == "__main__":
    T = 3
    arr = [1, 0, 5, 5, 2, 6]
    N = len(arr)
 
    numbersOccurringOnce(arr, N, T)


C#




using System;
using System.Collections.Generic;
using System.Threading;
 
// Structure of subarray of the array
class RangeInfo {
    // Stores start index of the subarray
    public int start;
 
    // Stores end index of the subarray
    public int end;
 
    // Stores pointer to the first array element
    public int[] a;
 
    public RangeInfo(int start, int end, int[] a)
    {
        this.start = start;
        this.end = end;
        this.a = a;
    }
}
 
public class GFG {
 
    // Declaring map for thread exclusion(lock)
    static Dictionary<int, int> mp
        = new Dictionary<int, int>();
 
    // Function performed by every thread to
    // count the frequency of array elements
    // in current subarray
    static void func(RangeInfo rptr)
    {
        // Thread is going through the array
        // to check and update the map
        for (int i = rptr.start; i <= rptr.end; i++) {
            // Stores value of the current element
            int curr = rptr.a[i];
 
            // Synchronize access to the map
            lock(mp)
            {
                // Stores the frequency of the current
                // element
                int freq;
                mp.TryGetValue(curr, out freq);
 
                // If curr not found in map mp
                if (freq == 0) {
                    // Insert curr with frequency 1
                    mp.Add(curr, 1);
                }
                else {
                    // Update frequency of current element
                    mp[curr] = freq + 1;
                }
            }
        }
    }
 
    // Function to find the unique numbers in the array
    static void numbersOccurringOnce(int[] arr, int n,
                                     int t)
    {
        // Stores all threads
        Thread[] threads = new Thread[t];
 
        // Stores start index of first thread
        int spos = 0;
 
        // Stores last index of the first thread
        int epos = spos + (n / t) - 1;
 
        // Traverse each thread
        for (int i = 0; i < t; i++) {
            // Update start index of current subarray
            int start = spos + (n / t) * i;
 
            // Stores end index of current subarray
            int end = i == t - 1
                          ? n - 1
                          : spos + (n / t) * (i + 1) - 1;
 
            // Initialize range_info for current thread
            RangeInfo rptr = new RangeInfo(start, end, arr);
 
            // creating each thread with appropriate
            // parameters
            threads[i] = new Thread(() => func(rptr));
        }
 
        // Starting all threads
        for (int i = 0; i < t; i++) {
            threads[i].Start();
        }
 
        // Waiting for threads to finish
        for (int i = 0; i < t; i++) {
            threads[i].Join();
        }
 
        // Traverse the map
        foreach(KeyValuePair<int, int> entry in mp)
        {
            // If frequency of current element is 1
            if (entry.Value == 1) {
                // Print the element
                Console.Write(entry.Key + " ");
            }
        }
    }
 
    // Driver's Code
    public static void Main(string[] args)
    {
        int T = 3;
        int[] arr = { 1, 0, 5, 5, 2, 6 };
        int N = arr.Length;
 
        numbersOccurringOnce(arr, N, T);
    }
}


Javascript




// Structure of subarray of the array
class RangeInfo {
    // Stores start index of the subarray
    constructor(start, end, a) {
        this.start = start;
        this.end = end;
        this.a = a;
    }
}
 
// Declaring map for thread exclusion(lock)
let mp = {};
 
// Function performed by every thread to
// count the frequency of array elements
// in the current subarray
async function func(rptr) {
    // Thread is going through the array
    // to check and update the map
    for (let i = rptr.start; i <= rptr.end; i++) {
        // Stores the value of the current element
        let curr = rptr.a[i];
 
        // Synchronize access to the map
        // Note: JavaScript does not have a direct equivalent of Python's threading.Lock(),
        // so we'll use a simple object for synchronization
        let lock = {};
        lock.acquire = function () {};
        lock.release = function () {};
 
        lock.acquire();
        // Stores the frequency of the current
        // element
        let freq = mp[curr] || 0;
 
        // If curr not found in map mp
        if (freq === 0) {
            // Insert curr with frequency 1
            mp[curr] = 1;
        } else {
            // Update frequency of the current element
            mp[curr] = freq + 1;
        }
        lock.release();
    }
}
 
// Function to find the unique numbers in the array
async function numbersOccurringOnce(arr, n, t) {
    // Stores all Promises
    let promises = [];
 
    // Stores start index of the first thread
    let spos = 0;
 
    // Stores the last index of the first thread
    let epos = spos + Math.floor(n / t) - 1;
 
    // Traverse each thread
    for (let i = 0; i < t; i++) {
        // Update the start index of the current subarray
        let start = spos + Math.floor(n / t) * i;
 
        // Stores the end index of the current subarray
        let end = i === t - 1 ? n - 1 : spos + Math.floor(n / t) * (i + 1) - 1;
 
        // Initialize range_info for the current thread
        let rptr = new RangeInfo(start, end, arr);
 
        // Creating each Promise with appropriate
        // parameters
        promises.push(func(rptr));
    }
 
    // Wait for all Promises to resolve
    await Promise.all(promises);
 
    // Traverse the map
    for (let [key, value] of Object.entries(mp)) {
        // If the frequency of the current element is 1
        if (value === 1) {
            // Print the element
            console.log(key, " ");
        }
    }
}
 
// Drivers Code
let T = 3;
let arr = [1, 0, 5, 5, 2, 6];
let N = arr.length;
 
numbersOccurringOnce(arr, N, T);
 
// This code is contributed by Kanchan Agarwal


Time Complexity: O(N * log(N))
Auxiliary Space: O(N)

Note: It is recommended to execute the program in a Linux based system using the following command:

g++ -pthread program_name.cpp



Last Updated : 05 Feb, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads