1

In C++ how i can write two parallel threads which will work one by one.For example in below code it need to print 0 t 100 sequentially.In below code the numbers are printing ,but all are not sequential.I need to print like 1,2,3,4,5,6.....99.If any body know , try to add with sample code also.

    #pragma once
#include <mutex>
#include <iostream>
#include <vector>
#include <thread>
#include <condition_variable>
using namespace std;
class CuncurrentThread
{
public:
    mutex mtx;
    condition_variable cv;
    static bool ready;
    static bool processed;
    void procThread1()
    {
        for (int i = 0; i < 100; i += 2)
        {
            unique_lock<mutex> lk(mtx);
            cv.notify_one();
            if(lk.owns_lock())
                cv.wait(lk);
            cout << "procThread1 : " << i << "\n";
            lk.unlock();
            cv.notify_one();
        }
    };
    void procThread2()
    {
        for (int i = 1; i < 100; i += 2)
        {
            unique_lock<mutex> lk(mtx);
            cv.notify_one();
            if (lk.owns_lock())
                cv.wait(lk);
            cout << "procThread2 : " << i << "\n";
            lk.unlock();
            cv.notify_one();
        }
    };
    static void ThreadDriver(CuncurrentThread* thr)
    {
        vector<thread> threads;
        threads.push_back(thread(&CuncurrentThread::procThread1, thr));
        threads.push_back(thread(&CuncurrentThread::procThread2, thr));

        for (auto& thread : threads) 
            thread.join();

    };
};
bool CuncurrentThread::ready = false;
int main()
{
    CuncurrentThread tr;
    CuncurrentThread::ThreadDriver(&tr);
    
}
Arun K
  • 61
  • 6
  • Why do you need two threads to write sequentially? What should each thread do then? Maybe your problem is that before the second thread is created, the first already finishes? In that case add some waiting/lock/sleep to the first thread to start them together. – Quimby Jan 19 '22 at 07:42
  • Do you mean that each time thread 1 prints 1 then thread 2 prints 1 then thread 1 prints 2 ... etc? In any case why let two threads be that tightly coupled? Maybe you want to explain what you want to do because this doesn't seem like a right solution. – Pepijn Kramer Jan 19 '22 at 07:42
  • @PepijnKramer no i updated the question.To print like 1,2,3,4,5....99 – Arun K Jan 19 '22 at 07:50
  • 2
    Not related to your question. But `#pragma once` is something you will use in a header and `using namespace std;` is something you don't want to use and especially not in a header. ([Why is "using namespace std;" considered bad practice?](https://stackoverflow.com/questions/1452721)) – t.niese Jan 19 '22 at 08:13
  • 1
    If you want to force two threads to run in lockstep you should be using just one thread. – Pete Becker Jan 19 '22 at 13:55

2 Answers2

1

Assuming you have a valid use case for using two threads like this, here is an example. I prefer using std::async over std::thread it has better abstraction and information exchange with the main thread. The example is written for 2 threads but can easily be changed to more threads.

Live demo here : https://onlinegdb.com/eQex9o_nMz

#include <future>
#include <condition_variable>
#include <iostream>

// Setup a helper class that sets up
// the three things needed to correctly
// use a condition variable
// 1) a mutex
// 2) a variable
// 3) a condition_variable (which is more of a signal then a variable)
//
// also give this class some functions
// so the the code becomes more self-explaining

class thread_switcher_t
{
public:
    void thread1_wait_for_turn()
    {
        std::unique_lock<std::mutex> lock{ m_mtx };
        m_cv.wait(lock, [&] {return (thread_number==0); });
    }

    void thread2_wait_for_turn()
    {
        std::unique_lock<std::mutex> lock{ m_mtx };
        m_cv.wait(lock, [&] {return (thread_number==1); });
    }

    void next_thread()
    {
        std::unique_lock<std::mutex> lock{ m_mtx };
        thread_number = (thread_number + 1) % 2;
        m_cv.notify_all();
    }

private:
    std::size_t thread_number{ 0 };
    std::mutex m_mtx;
    std::condition_variable m_cv;
};


int main()
{
    thread_switcher_t switcher;
    
    auto future1 = std::async(std::launch::async, [&]
    {
        for(std::size_t n = 0; n <= 100; n+=2)
        {
            switcher.thread1_wait_for_turn();
            std::cout << "thread 1 : " << n << "\n";
            switcher.next_thread();
        }
    });

    auto future2 = std::async(std::launch::async, [&]
    {
        for (std::size_t n = 1; n <= 100; n += 2)
        {
            switcher.thread2_wait_for_turn();
            std::cout << "thread 2 : " << n << "\n";
            switcher.next_thread();
        }
    });

    future1.get();
    future2.get();

    return 0;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19
0

You can use ready variable as a condition for condition variable.

#include <mutex>
#include <iostream>
#include <vector>
#include <thread>
#include <condition_variable>
using namespace std;

class CuncurrentThread
{
public:
    mutex mtx;
    condition_variable cv;
    static bool ready;
    //static bool processed;
    void procThread1()
    {
        for (int i = 0; i < 100; i += 2)
        {
            unique_lock<mutex> lk(mtx);
            // cv.notify_one();
            // if(lk.owns_lock())

            // wait until this condition is true i.e. until ready is false
            cv.wait(lk, [&]() { return !ready; });
            cout << "procThread1 : " << i << "\n";

            // set ready to true and notify waiting thread
            ready = true;
            lk.unlock();
            cv.notify_one();
        }
    };
    void procThread2()
    {
        for (int i = 1; i < 100; i += 2)
        {
            unique_lock<mutex> lk(mtx);
            // cv.notify_one();
            // if (lk.owns_lock())

            // wait until this condition is true i.e. until ready is true
            cv.wait(lk, [&]() { return ready; });
            cout << "procThread2 : " << i << "\n";

            // set ready to false and notify waiting thread
            ready = false;
            lk.unlock();
            cv.notify_one();
        }
    };
    static void ThreadDriver(CuncurrentThread* thr)
    {
        vector<thread> threads;
        threads.push_back(thread(&CuncurrentThread::procThread1, thr));
        threads.push_back(thread(&CuncurrentThread::procThread2, thr));

        for (auto& thread : threads) 
            thread.join();

    };
};
bool CuncurrentThread::ready = false;
int main()
{
    CuncurrentThread tr;
    CuncurrentThread::ThreadDriver(&tr);
}

Link where I tested this: https://godbolt.org/z/4jEns16oq

kiner_shah
  • 3,939
  • 7
  • 23
  • 37