user12034971
user12034971

Reputation:

How to make a function that can only be executed on one thread simultaneously?

I have a program that i am using to find prime numbers. it is executing on multiple threads. I am using the GetNextNumber() function for the threads to call to get a number to check if it is prime, however it seems that this function is being executed simultaneously by more than 1 thread, so sometimes two threads get the same number. here is my code:

#include "pch.h"
#include <cmath>
#include <fstream>
#include <thread>
#include <iostream>
#include <string>

int nextInt = 1;
std::ofstream file;

bool TestPrime(int number)
{
    double rootInt = sqrt(number);
    for (int i = 3; i <= rootInt; i += 2)
    {
        double divValue = (double)number / i;
        if (int(divValue) == divValue)
        {
            return false;
        }
    }
    return true;
}
int GetNextNumber()
{
    return (nextInt += 2);
}

void PrimeFinderThread()
{
    while (true)
    {
        int number = GetNextNumber();
        bool isPrime = TestPrime(number);
        if (isPrime)
        {
            std::string fileOutput = std::to_string(number) + "-";
            file << fileOutput;
        }
    }
}

int main() {
    file.open("primes.txt", std::ofstream::app);
    file << 2 << "-";
    std::thread threads[4];
    for (int i = 0; i < 4; i++) {
        threads[i] = std::thread(PrimeFinderThread);
    }
    for (int i = 0; i < 4; i++) {
        threads[i].join();
    }
    return 0;
}

Upvotes: 1

Views: 1005

Answers (2)

Thomas Sablik
Thomas Sablik

Reputation: 16453

Use a std::mutex with std::lock_guard. It will prevent simultaneous execution of the function.

#include "pch.h"
#include <cmath>
#include <fstream>
#include <thread>
#include <iostream>
#include <string>
#include <mutex>

int nextInt = 1;
std::ofstream file;

bool TestPrime(int number)
{
    double rootInt = sqrt(number);
    for (int i = 3; i <= rootInt; i += 2)
    {
        double divValue = (double)number / i;
        if (int(divValue) == divValue)
        {
            return false;
        }
    }
    return true;
}
int GetNextNumber()
{
    static std::mutex m;
    const std::lock_guard<std::mutex> lock(m);
    return (nextInt += 2);
}

void PrimeFinderThread()
{
    while (true)
    {
        int number = GetNextNumber();
        bool isPrime = TestPrime(number);
        if (isPrime)
        {
            std::string fileOutput = std::to_string(number) + "-";
            file << fileOutput;
        }
    }
}

int main() {
    file.open("primes.txt", std::ofstream::app);
    file << 2 << "-";
    std::thread threads[4];
    for (int i = 0; i < 4; i++) {
        threads[i] = std::thread(PrimeFinderThread);
    }
    for (int i = 0; i < 4; i++) {
        threads[i].join();
    }
    return 0;
}

Upvotes: 1

mpoeter
mpoeter

Reputation: 2949

Using a mutex is a valid solution, but in this case it causes unnecessary overhead. You can simply make nextId atomic:

std::atomic<int> nextId{1};

This makes the increment operation in GetNextNumber atomic, so no two threads will get the same value.

Upvotes: 2

Related Questions