Non-Repeating Elements of a given array using Multithreaded program
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 2Input: 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++ 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);
}
// C++ program to implement
// the above approach
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);
}
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);
}
}
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)
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);
}
}
// 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