Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
120 views
in Technique[技术] by (71.8m points)

c++ - Implementation of pattern "Multiplex" in c++11/14

Hey everybody and first of all forgive my poor english.

I have to implement the pattern "Multiplex" as described in "The Little Book of Semaphores" by Allen. B.Downey (it's a free resource).

I can't and I don't want use semaphores introduced in C++20 and so, only using mutex and condition variable, I came to the following code, maybe clumsy and twisted (spoiler):

/*
    PATTERN:    Multiplex

    TARGET:    allows multiple threads to run in the critical section at the
    same time, but it enforces an upper limit on the number of concurrent 
    threads. 
    In other words, no more than n threads can run in the critical section at 
    the same time
*/

//#include "stdafx.h"     // Only for MS Visual Studio
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <thread>
#include <string>
#include <vector>

using namespace std;

//#define IF_EXPIRES_ON_ONLINE_COMPILER        //    comment/uncomment it if you need

mutex mtx_IO;    //    No interleaved output

vector<int> deb_evolution_of_threads_In_CR;    //    only for debug purposes

const int iterationForcpuConsumer = 1000;

void cpuConsumer(thread::id tid)    //    the first thing that came to my fingers
{
#ifndef IF_EXPIRES_ON_ONLINE_COMPILER
    {
        lock_guard<mutex> lg(mtx_IO);
        cout << "
BEG cpuConsumer from #thread = " << tid;
    }

    string str = "str";
    for (int i = 0; i < iterationForcpuConsumer; ++i)
    {
        int j = i;
        try
        {
            str += str;
        }
        catch (...)
        {
            str = "";
        }
    }
    {
        lock_guard<mutex> lg(mtx_IO);
        cout << "
END cpuConsumer from #thread = " << tid;
    }
#else
    this_thread::sleep_for(chrono::milliseconds(1000));
#endif // !IF_EXPIRES_ON_ONLINE_COMPILER
}

const int totalNumThreadLaunched = 5;
const int upperLimitForThreadInCriticalRegion = 3;

const int nrOfIterations = 5;

mutex mtx_CR;
condition_variable cv;
int threads_In_CR = 0;

void threadLogic()
{
    for (int i = 0; i < nrOfIterations; ++i)
    {
        {
            lock_guard<mutex> lg(mtx_IO);
            cout << "
Elaboration that precedes the critical region for #thread = " << this_thread::get_id();
        }

        unique_lock<mutex> ul(mtx_CR);
        cv.wait(ul, []() {return (threads_In_CR < upperLimitForThreadInCriticalRegion); });
        ++threads_In_CR;
        deb_evolution_of_threads_In_CR.push_back(threads_In_CR);    //    only for debug purposes
        ul.unlock();

        cpuConsumer(this_thread::get_id());        //    Critical Region

        {
            lock_guard<mutex> lg(mtx_CR);
            --threads_In_CR;
            deb_evolution_of_threads_In_CR.push_back(threads_In_CR);    //    only for debug purposes
        }
        cv.notify_one();

        {
            lock_guard<mutex> lg(mtx_IO);
            cout << "
Elaboration that follows the critical region for #thread = " << this_thread::get_id();
        }
    }
}

int main()
{
    int DEBUG = 0;
    deb_evolution_of_threads_In_CR.push_back(0);

    vector<thread> vThreads;
    vThreads.reserve(totalNumThreadLaunched);
    for (int i = 0; i < totalNumThreadLaunched; ++i)
    {
        vThreads.push_back(thread(threadLogic));
    }

    for (int i = 0; i < totalNumThreadLaunched; ++i)
    {
        if (vThreads[i].joinable())
        {
            vThreads[i].join();
        }
    }

    for (auto i = deb_evolution_of_threads_In_CR.begin(); i != deb_evolution_of_threads_In_CR.end(); ++i)
    {
        cout << "
" << *i;
    }

    return 0;
}

Here a link to Coliru.

I thought and thought again, I analyzed and reanalyzed, I watched the outputs (but you know that they are not a proof) but now I need a comparison.

Can you tell if this code is correct? And if not, where are the traps? Every other suggestion about a better design (inside the constraints of C++11/14) is well accepted.

PS: I suppose that something might be declared 'atomic' (correct me if I'm wrong) but anyway I didn't study deeply the C++ memory model and so suggestions in that direction are well accepted in any case but, at the moment, these notions are not at the top issue list; if I suppose the I don't really know something I don't want use it.

Finally: can you suggest some metodology, some tool, somewhat that can guide the approach to this kind of code/problems? I was thinking to Petri Nets

Probably this will not be my last question about the implementation of some similar patterns, I hope it will also join you in the next discussions.

Thank for your attention and for your time

question from:https://stackoverflow.com/questions/65948044/implementation-of-pattern-multiplex-in-c11-14

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...