Skip to content
Related Articles

Related Articles

Improve Article

Non-Repeating Elements of a given array using Multithreaded program

  • Difficulty Level : Medium
  • Last Updated : 09 Jul, 2021

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);
}
Output: 
 

 

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

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :