Skip to content

Example: producer consumer and resource management

Hüseyin Tuğrul BÜYÜKIŞIK edited this page Feb 12, 2021 · 3 revisions

Here, resource management independency between "supply depot" and "virtual array" is shown with a "producer-consumer" example:

#include "GraphicsCardSupplyDepot.h"
#include "VirtualMultiArray.h"
#include "PcieBandwidthBenchmarker.h"

#include <thread>
#include <mutex>

const int MSG = 400;
std::mutex m;


template<typename T>
std::thread producer(VirtualMultiArray<T> arr, std::vector<T> & consumers)
{
        // pass-by-value test
	std::thread t([&,arr,consumers](){
		{
			std::unique_lock<std::mutex> lock(m);
			std::cout<<"Producer starting production....."<<std::endl;
		}
		for(auto & c:consumers)
		{
			{
				std::unique_lock<std::mutex> lock(m);
				std::cout<<"     id: "<<c<<std::endl;
			}
			arr.set(c,MSG);
		}

		std::unique_lock<std::mutex> lock(m);
		std::cout<<"producer produced things"<<std::endl;
	});

	return t;
}


template<typename T>
std::thread consumer(VirtualMultiArray<T> arr, const int idx)
{
        // pass-by-value test
	std::thread t([&,arr, idx](){
		while(MSG!=arr.get(idx)){
			std::this_thread::yield();
		}
		std::unique_lock<std::mutex> lock(m);
		std::cout<<std::string("consumer-")+std::to_string(idx)+ std::string(" consumed something")<<std::endl;
	});
	return t;
}

struct Resources
{
	// supply depot is not needed to out-live virtual array. Once VirtualMultiArray is created, supply depot can be destructed freely
	// but needs to be constructed first
	GraphicsCardSupplyDepot d;

	// 1 unique gpu channel per element to evade dead-lock between producer - consumer
	VirtualMultiArray<int> channels=VirtualMultiArray<int>(10,d.requestGpus(),1,1,{10,0,0,0,0,0},VirtualMultiArray<int>::MemMult::UseDefault,false);
	Resources(){}
};

int main(int argC, char ** argV)
{

	VirtualMultiArray<int> channels;

	{

		Resources r;

		// out-of-raii-scope testing
		channels = r.channels;

	}// here, "resources" is gone, but channels are still usable since virtual array's internal data is shared on a unique raw pointer

	// now, "channels" own/retain same opencl resource management from r.channels


	std::thread t[11];
	std::vector<int> idx;
	for(int i=0;i<10;i++)
	{
		idx.push_back(i);
		t[i]=consumer(channels,i); // 10 consumers own the same channels (pass-by-value) through shared_ptr-managed bits
	}

	t[10]=producer(channels,idx); // yet another instance of virtual array that point to same opencl environment

	for(int i=0;i<11;i++)
	{
		t[i].join();
	}


	return 0;
}