使用并行线程查找所有加起来等于给定数字的组合

时间:2019-05-20 00:35:54

标签: c++ windows multithreading winapi visual-c++

问题是找到一种方法来达到与以下代码中已达到的结果相同的结果,但是要使用自定义数量的线程,使用临界区和信号量,以便并行化以下代码

我试图并行化代码的递归部分,但是我没有提出任何合理的解决方案

这里的代码可以以某种方式并行化,信号量可以用来并行化代码,但尚不清楚可以并行运行哪些部分


已经在运行的解决方案:

C ++程序找出所有的组合 加上给定数字的正数

#include <iostream> 
using namespace std; 

//    arr - array to store the combination 
//    index - next location in array 
//    num - given number 
//    reducedNum - reduced number 

void findCombinationsUtil(int arr[], int index, 
                       int num, int reducedNum) 
{ 
    // Base condition 
    if (reducedNum < 0) 
        return; 

    // If combination is found, print it 
    if (reducedNum == 0) 
    { 
        for (int i = 0; i < index; i++) 
            cout << arr[i] << " "; 
        cout << endl; 
        return; 
    } 

    // Find the previous number stored in arr[] 
    // It helps in maintaining increasing order 
    int prev = (index == 0)? 1 : arr[index-1]; 

    // note loop starts from previous number 
    // i.e. at array location index - 1 
    for (int k = prev; k <= num ; k++) 
    { 
        // next element of array is k 
        arr[index] = k; 

        // call recursively with reduced number 
        findCombinationsUtil(arr, index + 1, num, 
                                 reducedNum - k); 
    } 
} 

查找所有组合的功能 加上给定数字的正数。 它使用findCombinationsUtil()

void findCombinations(int n) 
{ 
    // array to store the combinations 
    // It can contain max n elements 
    int arr[n]; 

    //find all combinations 
    findCombinationsUtil(arr, 0, n, n); 
} 

驱动程序代码

int main() 
{ 
    int n = 5; 
    findCombinations(n); 
    return 0; 
} 

来源:https://www.geeksforgeeks.org/find-all-combinations-that-adds-upto-given-number-2/

2 个答案:

答案 0 :(得分:1)

我将引用另一个答案中的一句话:

  

我将采取建议路线。在尝试使用线程提高程序速度之前,首先要在单线程情况下提高程序速度。

在您的特定问题中,我认为以某种方式并行化该函数非常困难。例如,您可以让每个线程在原始数组的子数组中找到数字的组合,但是不同子数组中的组合又如何呢?显然,并行化此问题是有限制的,因为每个数字都依赖于每个其他数字。 您可以在进行并行计算之前预先对总和进行缓存,但是如果您希望数字构成组合,将无济于事。

有关更多信息,请参见这些链接。

https://www.codeproject.com/Articles/1247260/Cplusplus-Simple-Permutation-and-Combination-Paral

Parallelizing recursive function using OpenMP in C++

答案 1 :(得分:0)

好的,有一个合理的解决方案,每个固定数量的和使用一个线程,即5个数字的和是1个线程,4个数字的和是另一个线程,而3个数字的和是另一个线程。 。这样我们就可以使用逻辑核心来处理计算了!

在当前情况下,我不是专业人士(我不假装不是专业人士),这不是完美的解决方案,但它解决了使用并行线程的既定任务,并且有效:

#include "stdafx.h"
#include <fstream>
#include <string>
#include <iostream>
#include <vector>
#include <Windows.h>
#include <chrono>
#include <queue>

typedef int ReverseIterator;

//#define SHOW_RESULTS

CRITICAL_SECTION cs;
HANDLE sem;
HANDLE* threads;

//using namespace std;
std::ifstream g_inputStream;
std::ofstream g_outputStream;

int g_threadCount;
int g_countOfCombinations = 0;
int g_targetNumber = 0;
std::string g_millisecondsSpentOutputStr;

namespace Set {
    class ContainerSet {
    public:
        bool _empty;
        int _size;
        int* _collection;
        int _lastIndex;
        ContainerSet* next;
        ContainerSet()
        {
            _lastIndex = 0;
            _size = 0;
            _collection = nullptr;
            _empty = true;
        }

        ContainerSet(const ContainerSet& source)
        {
            Initialize(source);
        }

        void Initialize(const ContainerSet& source)
        {
            _lastIndex = 0;
            _size = source._size;
            _collection = new int[_size];

            for (int i = 0; i < _size; i++) {
                _collection[i] = source[i];
            }
            _empty = false;
        }

        ContainerSet(int size) 
        {
            _lastIndex = 0;
            _collection = new int[size];
            _size = size;
            _empty = false;
        }

        ~ContainerSet() 
        {
            if (_empty == true)
                return;
            else {
                if (_collection) {
                    delete _collection;
                    _collection = nullptr;
                    _empty = true;
                }
            }
        }

        int operator[] (int i) const {
            if (_collection == nullptr)
                return -1;
            return _collection[i];
        }

        int& operator[](int i) {
            if (_collection == nullptr)
                return _collection[0];
            return _collection[i];
        }

        bool operator<(const ContainerSet& left) 
        {
            return left._collection < this->_collection;
        }

        int size() { if (this == nullptr) return 0; return _size; }

        bool Equal(ContainerSet* set) {
            if (_collection == nullptr || _size < 0 )
                return false;

            for (int i = 0; i < set->size(); i++)
            {
                if (set->_collection[i] != this->_collection[i])
                    return false;
            }
            if(set->size() == this->size())
                return true;
            return false;
        }

        int* rbegin() { return &_collection[_size - 1]; }
        int* rend() { return &_collection[0]; }
        int* begin() { return &_collection[0]; }
        int* end() { return &_collection[_size - 1]; }
    };


    class DynamicListOfSets {
        public:
            bool _empty;
            ContainerSet* _last;
            ContainerSet* _first;
            DynamicListOfSets()
            {
                Initialize(this);
            }
            static void Initialize(DynamicListOfSets* list) {

                list->_first = nullptr;
                list->_last = nullptr;
            }
            ContainerSet* back() {
                return _last;
            }
            bool HasEqualMember(ContainerSet* member)
            {
                if (_first == nullptr)
                {
                    return false;
                }
                ContainerSet* current = _first;
                do {
                    //do stuff
                    if (current->Equal(member))
                        return true;

                    current = current->next;
                } while (current->next != nullptr);
                return false;
            }

            ContainerSet* front() 
            {
                return _first;
            }
            void push_back(ContainerSet* set)
            {
                if (set == nullptr)
                    return;

                set->next = nullptr;
                if (_last == nullptr) {
                    _first = set; _last = set;
                } else {
                    _last->next = set;
                    _last = set;
                }
                _empty = false;
            }

            void clear() {
                ContainerSet* current = _first;
                if (current == nullptr) {
                    _empty = true;
                    return;
                }
                ContainerSet* next = current->next;

                do {
                    //extract next from current
                    next = current->next;
                    //delete current
                    delete current;
                    //move next 
                    current = next;
                    //if next exist
                } while (next != nullptr);

                _empty = true;
            }
            void pop_front() {
                if (_first != nullptr)
                {
                    auto next = _first->next;
                    delete _first;
                    if (next != nullptr)
                        _first = next;
                }
            }
            ~DynamicListOfSets()
            {
                _empty = true;
            }
    };

    class ListOfSets {
    public:
        //data fields
        ContainerSet** _collection;
        int _size;
        int _pointer;

        ContainerSet* operator[] (int i) const {
            if (_collection == nullptr)
                return nullptr;
            return _collection[i];
        }

        //constructors
        ListOfSets()
        {
            _size = 0;
            _collection = nullptr;
            _pointer = -1;
        }

        ListOfSets(int size)
        {
            Initialize(this, size);
        }

        static void Initialize(ListOfSets* list, int size)
        {
            list->_size = size;
            list->_collection = new ContainerSet*[size];
            for (int i = 0; i < size; i++)
            {
                list->_collection[i] = new ContainerSet(size);
            }
            list->_pointer = -1;
        }

        //methods
        int size()
        {
            return _size;
        }

        void push_back(ContainerSet* list)
        {
            if (!IsFull())
            {
                if (list == nullptr)
                {
                    //TODO: check and correct here
                    throw 0;
                    return;
                }
                _pointer++;
                _collection[_pointer] = list;
            }
        }

        ContainerSet* next(int index)
        {
            if ( (index+1) >= _size)
                return nullptr;
            return _collection[index + 1];
        }

        ContainerSet* front()
        {
            if(_collection != nullptr)
                return _collection[0];
            return nullptr;
        }

        ContainerSet* pop_back()
        {
            if (!HasValues())
                return nullptr;
            else {
                if(_pointer-1 >= 0)
                    return _collection[_pointer--];
                return false;
            }
        }

        ContainerSet* pop_front()
        {
            if (!HasValues())
                return nullptr;
            else {
                if (_pointer >= 0)
                    return _collection[0];
                return false;
            }
        }

        bool IsFull()
        {
            return (_pointer + 1) >= _size;
        }
        bool HasValues()
        {
            if (_collection == nullptr || _size <= 0)
                return false;
            return true;
        }

        ContainerSet* rbegin()
        {
            if (_collection == nullptr || _collection[_size - 1] == nullptr) 
                return nullptr;
            return _collection[_size - 1];
        }
        ContainerSet* rend()
        {
            if (_collection == nullptr || _collection[0] == nullptr)
                return nullptr;
            return _collection[0];
        }
        ContainerSet* begin()
        {
            if (_collection == nullptr || _collection[0] == nullptr)
                return nullptr;
            return _collection[0];
        }
        ContainerSet* end()
        {
            if (_collection == nullptr || _collection[_size - 1] == nullptr)
                return nullptr;
            return _collection[_size - 1];
        }

        void clear()
        {
            if (_collection == nullptr)
                return;
            if (_collection[0]) {
                for (int cSI = 0; cSI < _size; cSI++)
                {
                    if (_collection[cSI] != nullptr)
                    {
                        delete _collection[cSI];
                        _collection[cSI] = new Set::ContainerSet();
                    }
                }
            }
            ListOfSets();
        }

        ~ListOfSets() {
            clear();
        }
    };
}

typedef Set::ContainerSet SolutionIntContainer;

namespace SimpleTimer {
    class SimpleTimer
    {
    public:
        SimpleTimer::SimpleTimer()
        {
            start = std::chrono::high_resolution_clock::now();
            stopped = false;
        }

        std::string SimpleTimer::Stop()
        {
            end = std::chrono::high_resolution_clock::now();
            duration = end - start;
            float result = duration.count();
            std::string strResult;

            strResult.append("Time spent: ");
            strResult.append(std::to_string(result));
            strResult.append("seconds");
            strResult.append("\n");
            return strResult;
        }

        std::string SimpleTimer::StopMilliseconds()
        {
            stopped = true;
            end = std::chrono::high_resolution_clock::now();
            duration = end - start;
            auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
            std::string strResult;

            strResult.append(std::to_string(millis));
            return strResult;
        }

        SimpleTimer::~SimpleTimer()
        {
            if (stopped)
                return;
            end = std::chrono::high_resolution_clock::now();
            duration = end - start;
            float result = duration.count();
            std::cout << "Time spent: " << result << " seconds" << std::endl;
        }
    private:
        std::chrono::time_point<std::chrono::steady_clock> start, end;
        std::chrono::duration<float> duration;
        bool stopped;
    };
}

namespace NewSolution {

    bool Equal(SolutionIntContainer* left, SolutionIntContainer* right) {
        for (int i = 0; i < (left->size() - 1); i++) {
            if ((*left)[i] != (*right)[i])
                return false;
        }

        return true;
    }

    int Difference(int sum) {
        return g_targetNumber - sum;
    }

    int Difference(SolutionIntContainer& targetList) {
        int sum = 0;
        for (auto it = targetList.rbegin(); it >= targetList.rend(); it--) {
            sum += (*it);
        }
        return Difference(sum);
    }

    class CombinationStorage {
    private:
        Set::DynamicListOfSets descendants;
    public:
        // constructors 
        CombinationStorage(int size) {
            Set::DynamicListOfSets::Initialize(&descendants);
        }

        // methods
        void DeleteDescendants() {
            //descendants.clear();
        }

        bool FindDescendant(SolutionIntContainer* sIC) {

            auto it = descendants.front();
            while (it != nullptr) {
                if (Equal(it, sIC))
                    return true;
                it = it->next;
            } 

            return false;
        }
        void AddDescendant(SolutionIntContainer* combinationNode) {
            if (combinationNode != nullptr)
                descendants.push_back(new SolutionIntContainer(*combinationNode));
        }

        SolutionIntContainer* GetNextDescendant() {
            return descendants.front();
        }
        void DeleteFrontDescendant() {
            descendants.pop_front();
        }

    }; // class CombinationComparator

    class ListHandler {
    private:
        CombinationStorage combinationStorage;
        SolutionIntContainer sourceList;
    public:
        // public fields:
        static Set::ListOfSets startingCombinations;

        //constructor:
        ListHandler(SolutionIntContainer* s, int size) : combinationStorage(size)
        {
            sourceList.Initialize(*s);
            //InitializeCombinations();
        }

        //methods:
        void DeleteInnerDescendants()
        {
            combinationStorage.DeleteDescendants();
        }

        void NewDescendantFound(SolutionIntContainer* combination)
        {
            g_countOfCombinations++;
            combinationStorage.AddDescendant(combination);
        }

        void CombinationFound(SolutionIntContainer* combination) {
            g_countOfCombinations++;
        }

        bool RightIsGreaterOrEqual(int left, int right) {
            if (right >= left)
                return true;
            return false;
        }

        int IncludingIndexDifference(int sum, int reductionOffset)
        {
            return ((g_targetNumber - reductionOffset) - sum);
        }

        //Tested OK 10:47 PM 5/23/2019
        bool CheckOrder(SolutionIntContainer& list, int maxIndex)
        {
            // TODO: optimize 
            int leftI = 0, rightI = 1;
            int sum = list[leftI];
            for (; rightI <= maxIndex; leftI++, rightI++) {
                if (!RightIsGreaterOrEqual(list[leftI], list[rightI]))
                    return 1;
                sum += list[rightI];
            }

            int reductionOffset = 0;
            for (int i = (rightI + 1); i < list.size(); i++)
            {
                reductionOffset += list[i];
            }

            return IncludingIndexDifference(sum, reductionOffset);
        }

        static void ShowList(SolutionIntContainer& list, std::string* additionalContents = nullptr, bool reversed = false)
        {
#ifdef SHOW_RESULTS
            if (reversed) {
                for (auto i = list.rbegin(); i >= list.rend(); i--)
                {
                    std::cout << (*i) << " ";
                }
            }
            else {
                for (auto i = list.begin(); 
                    i <= list.end(); 
                    i++) {
                    std::cout << (*i) << " ";
                }
            }
            if (additionalContents != nullptr) {
                std::cout << " \t " << *additionalContents << " \t ";
            }
            std::cout << std::endl;
#endif
        }

        static void ShowCombination(SolutionIntContainer& container, std::string* additionalContents = nullptr, bool reversed = false) {
#ifdef SHOW_RESULTS
            std::cout << g_countOfCombinations << ") \t";
            ShowList(container, additionalContents, reversed);
#endif
        }

        void Inc(SolutionIntContainer& list, int index, int count = 1) {

            if (index < 0 || index >= list.size())
                return;
            list[index] = list[index] + count;
        }

        void Dec(SolutionIntContainer& list, int index) {
            if (index < 0 || index >= list.size())
                return;
            list[index] = list[index] - 1;
        }

        void TryDecAndInc(SolutionIntContainer& newList, SolutionIntContainer& oldList, int reductionIndex, int increasingIndex)
        {
            newList.Initialize(oldList);
            Dec(newList, reductionIndex);
            Inc(newList, increasingIndex);
        }       

        SolutionIntContainer& TryDecAndInc(SolutionIntContainer& const newList, int reductionIndex, int increasingIndex)
        {
            Dec(newList, reductionIndex);
            Inc(newList, increasingIndex);
            return newList;
        }

        bool RebuildDownstairs(SolutionIntContainer& list, int rightI, int leftI = -1)
        {
            if (leftI == -1)
                leftI = rightI - 1;

            SolutionIntContainer newTryList;
            TryDecAndInc(newTryList, list, rightI, leftI);

            if (CheckOrder(newTryList, rightI) > 0)
                return false;

            if (!combinationStorage.FindDescendant(&newTryList)) {
                NewDescendantFound(&newTryList);

                list[rightI] = list[rightI] - 1;
                list[leftI] = list[leftI] + 1;

#ifdef SHOW_RESULTS
                std::string indexesStr = std::string("rightIndex = ") + std::to_string(rightI) +
                    +" ; " + std::string("leftIndex = ") + std::to_string(leftI) + std::string(";");

                ShowCombination(list
                    , &indexesStr
                );
#endif //SHOW_RESULTS
                return true;
            }
            return false;
        }

        bool GlidePossible(SolutionIntContainer& sIC)
        {
            int first = sIC[0];
            int last = sIC[sIC.size() - 1];
            int offset = 1;

            if (last > (first + offset))
            {
                return true;
            }
            return false;
        }

        int startingLeftLeftIndex;
        bool glode = false;
        int lastRight = 1;
        int lastLeft = 1;

        bool Exists(SolutionIntContainer& list, int minR, int maxL) {
            if (minR == lastRight && maxL == lastLeft)
                return true;
            return false;
        }

        void TryGhostGlideALine(SolutionIntContainer& list, int rightIndex, int leftLeftI,
            int& depthOverall, int currentDepth)
        {
            SolutionIntContainer newTryList(list);

            while (depthOverall == currentDepth) //(true)
            {
                if (leftLeftI < 0) {
                    leftLeftI = startingLeftLeftIndex;
                }

                if (!GlidePossible(newTryList))
                    return;
                TryDecAndInc(newTryList, rightIndex, leftLeftI);

                if (CheckOrder(newTryList, rightIndex) <= 0) {
                    if (
                        !combinationStorage.FindDescendant(&newTryList)
                        ) {
                        NewDescendantFound(&newTryList);

                        //if(newTryList[rightIndex] < lastRight)
                            lastRight = newTryList[rightIndex];
                        //if (newTryList[leftLeftI] > lastLeft)
                            lastLeft = newTryList[leftLeftI];

                        ShowCombination(newTryList);
                    }

                    TryGhostGlideALine(newTryList, rightIndex, leftLeftI, ++depthOverall, ++currentDepth);

                    // Repeat recursively
                    TryGhostGlideALine(newTryList, rightIndex, (leftLeftI - 1),
                        (depthOverall = currentDepth),
                        /*++*/currentDepth
                    );
                } else {
                    return;
                }
                leftLeftI--;
            }
        }

        void ChangeValue(SolutionIntContainer& container, int index, int value) {
            container[index] = value;
        }

        bool CanDecRightAndIncLeft(SolutionIntContainer& list, int rightI, int leftI) {
            return CheckOrder(TryDecAndInc(list, rightI, leftI), rightI) <= 0;
        }

        bool FindNext(SolutionIntContainer& list, int rightI)
        {
            bool result = true;

            // working with previous
            // Find the left Element
            // Check if left element is to the left of right
            int leftI = (rightI - 1);

            // exit if can't shift
            // (exit if left doesn't exist)
            if (leftI < 0)
                return false;

            // TODO: exit condition
            if (!RebuildDownstairs(list, rightI))
                return false;

            // a third element we are currently working on 
            // it is to the third position to the left 
            // and more if needed 
            int leftLeftI = (leftI - 1);
            if (leftLeftI >= 0)
            {
                startingLeftLeftIndex = leftLeftI;
                int depth = 0;

                lastRight = list[rightI];
                lastLeft = 1;
                //TODO: check if works
                combinationStorage.DeleteDescendants();
                TryGhostGlideALine(list, rightI, leftLeftI, depth, depth//, 0
                );
            }

            // Ghost Glide OK, continue
            return result;
        }

        // Rebuild saving existing right element
        bool RebuildCombination(SolutionIntContainer& list,
            ReverseIterator rightIndex)
        {
            if (rightIndex <= 0)
                return false;
            // strictly more than 0 because we move towards left border
            // and check for the previous (right - 1) element

            int orderDisplacement = CheckOrder(list, rightIndex);

            if (orderDisplacement < 0)
                Inc(list, rightIndex);
            if (orderDisplacement > 0)
                return false;

            int leftI = (rightIndex - 1);

            // Find the changed
            while (FindNext(list, rightIndex)) {

            }
            return true;
        }

        static void InitializeCombinations( int count )
        {
            Set::ListOfSets::Initialize(&startingCombinations, count-1);
            for (int i = count; i > 1; i--)
            {
                SolutionIntContainer* newList = new SolutionIntContainer(i);
                for (int k = 0; k < i; k++) {
                    (*newList)[k] = 1;
                }

                startingCombinations.push_back(newList);
            }
        }

        void FindAllSumsFixedLength()
        { 
            ShowList(sourceList);
            int rightIndex = /*firstRun ?*/ sourceList.size() - 1 /*: iterator - 1*/;
            int left = (rightIndex - 1);
            int difference = g_targetNumber;

            while ((difference = NewSolution::Difference(sourceList)) > 0) {
                sourceList[rightIndex]++;
            }

            NewDescendantFound(&sourceList);
            ShowCombination(sourceList);

            while (
                RebuildCombination(sourceList, rightIndex)
                )
            {
                --rightIndex;
            }
        }

        static SolutionIntContainer Next()
        {
            EnterCriticalSection(&::cs);
            if (startingCombinations.size() == 0)
                return SolutionIntContainer(0);

            SolutionIntContainer* sourceList = startingCombinations.pop_front();

            LeaveCriticalSection(&::cs);
            return *sourceList;
        }

        static void WriteLineThreadBlocking(const char* line, int length = 0)
        {
            EnterCriticalSection(&::cs);
            std::cout << line << std::endl;
            LeaveCriticalSection(&::cs);
        }

        static DWORD WINAPI FindAllSumsFixedLengthMT(LPVOID pListHandler)
        {
            ListHandler* pLH = (ListHandler*)pListHandler;

            DWORD dwWaitResult;
            BOOL bContinue = TRUE;

            // Try to enter the semaphore gate.

            dwWaitResult = WaitForSingleObject(
                sem,        // handle to semaphore
                INFINITE);  // zero-second time-out interval

            int rightIndex = 0;
            int left = 0;
            int difference = g_targetNumber;

            switch (dwWaitResult)
            {
                // The semaphore object was signaled.
            case WAIT_OBJECT_0:
                //// TODO: Perform task
                bContinue = FALSE;

                rightIndex = /*firstRun ?*/ pLH->sourceList.size() - 1 /*: iterator - 1*/;
                left = (rightIndex - 1);

                //TODO: test Added 9/24/2019
                if (rightIndex < 0)
                    return FALSE;
                while ((difference = NewSolution::Difference(pLH->sourceList)) > 0) {
                    pLH->sourceList[rightIndex]++;
                }

                pLH->NewDescendantFound(&pLH->sourceList);
                ShowCombination(pLH->sourceList);

                while (
                    pLH->RebuildCombination(pLH->sourceList, rightIndex)
                    )
                {
                    --rightIndex;
                }
                pLH->combinationStorage.DeleteDescendants();

                // Release the semaphore when task is finished

                if (!ReleaseSemaphore(
                    sem,  // handle to semaphore
                    1,            // increase count by one
                    NULL))       // not interested in previous count
                {
                    //printf("ReleaseSemaphore error: %d\n", GetLastError());
                }
                break;

                // The semaphore was nonsignaled, so a time-out occurred.
            case WAIT_TIMEOUT:
                //printf("Thread %d: wait timed out\n", GetCurrentThreadId());
                break;
            }
            delete pLH;
            return TRUE;
        }

    }; // CombinationListHandler
} // New Solution //

Set::ListOfSets NewSolution::ListHandler::startingCombinations;

bool InitializeStreams()
{
    try {
        g_inputStream = std::ifstream();
        g_inputStream.open("input.txt");

        g_outputStream = std::ofstream();
        g_outputStream.open("output.txt", std::ios::trunc);

        return true;
    } catch (...) {
        return false;
    }
}

void Output()
{
    g_outputStream << g_threadCount;
    g_outputStream << std::endl;

    g_outputStream << g_targetNumber;
    g_outputStream << std::endl;

    g_outputStream << g_millisecondsSpentOutputStr;
    g_outputStream << std::endl;
}

void CloseStreams() 
{
    g_inputStream.close();
    g_outputStream.close();
}

bool InitializeInputData() {
    try {

        g_threadCount = -1;
        g_targetNumber = -1;

        // Read count of threads from the file
        std::string tempLine;
        std::getline(g_inputStream, tempLine);
        g_threadCount = std::stoi(tempLine);

        // Read the target number from the file
        std::getline(g_inputStream, tempLine);
        g_targetNumber = std::stoi(tempLine);;

        if (g_threadCount == -1 || g_targetNumber == -1) {
            return false;
        }
    } catch (...) {
        return false;
    }

    return true;
}

void RunNewSolutionMultiThreaded() {

    SimpleTimer::SimpleTimer simpleTimer = SimpleTimer::SimpleTimer();
    g_countOfCombinations = 0;
    NewSolution::ListHandler::InitializeCombinations(g_targetNumber);

    for (int i = 0
        ; i < NewSolution::ListHandler::startingCombinations.size(); 
        i++)
    {
        NewSolution::ListHandler::ShowList(*NewSolution::ListHandler::startingCombinations[i]);
    }

    sem = CreateSemaphore(
        NULL,           // default security attributes
        1,              // initial count
        g_threadCount,  // maximum count
        NULL);          // unnamed semaphore


    if (sem == NULL)
    {
        printf("CreateSemaphore error: %d\n", GetLastError());
    }

    // Initialize the critical section one time only.
    if (!InitializeCriticalSectionAndSpinCount(&cs,
        0x00000400))
        return;

    // Create worker threads
    DWORD ThreadID;
    threads = new HANDLE[NewSolution::ListHandler::startingCombinations.size()];

    for (int i = 0; i < NewSolution::ListHandler::startingCombinations.size(); i++)
    {
        threads[i] = 0;
    }

    int lastThreadID = -1; int i = 0;

    for (int i = 0; 
        i < NewSolution::ListHandler::startingCombinations.size(); 
        i++
        )
    {
        auto it = NewSolution::ListHandler::startingCombinations._collection[i];
        if (NewSolution::Difference(*it) == 0) {
            g_countOfCombinations++;
            //NewSolution::ListHandler::ShowCombination(*it);
            continue;
        }
        ++lastThreadID;
        NewSolution::ListHandler* listHandler = new NewSolution::ListHandler(it, it->size());

        listHandler->DeleteInnerDescendants();

        //listHandler->FindAllSumsFixedLength();

        threads[lastThreadID] = CreateThread(
            NULL,       // default security attributes
            0,          // default stack size
            (LPTHREAD_START_ROUTINE)NewSolution::ListHandler::FindAllSumsFixedLengthMT,
            (LPVOID)listHandler,       // thread function argument
            0,          // default creation flags
            &ThreadID); // receive thread identifier

        if (threads[lastThreadID] == NULL)
        {
            printf("CreateThread error: %d\n", GetLastError());
            return;
        }
    }

    // Wait for all threads to terminate
    WaitForMultipleObjects(lastThreadID + 1, threads, TRUE, INFINITE);

    // Close thread and semaphore handles
    for (int i = 0; i <= lastThreadID; i++)
        CloseHandle(threads[i]);

    delete[] threads;
    CloseHandle(sem);

    // Release resources used by the critical section object.
    DeleteCriticalSection(&cs);

    //NewSolution::ListHandler::startingCombinations.~ListOfSets();

    std::cout << "Count of combinations " << g_countOfCombinations /*+ g_targetNumber-1*/ << std::endl;
    std::cout << "*** New Solution Execution Completed ***" << std::endl;

    // Counting time spent
    g_millisecondsSpentOutputStr = simpleTimer.StopMilliseconds();
    std::cout << "Time spent: " << g_millisecondsSpentOutputStr << std::endl;
}


int main()
{
    g_countOfCombinations = 0;

    if (
        !InitializeStreams()
    ) {
        std::cout << "File \"input.txt\" doesn't exist. Quiting..." << std::endl;
        system("pause");
        return 1;
    }

    if ( !InitializeInputData() ) {
        std::cout << "Input file is currupted... Quiting..." << std::endl;
        system("pause");
        return 1;
    }

    RunNewSolutionMultiThreaded();

    Output();
    CloseStreams();
    system("pause");

    return 0;
}