0

I have written a code that takes directory as input and outputs list of files in it.I implemented it in single thread.what to do in order to implement using multiple threads? provide me logic or code.

Platform : Windows API: Windows.h Language: c++

    #include <iostream>
    #include <Windows.h>
    #include <queue>
    #include <TlHelp32.h>
    #include <string>
    #include <vector>

    using namespace std;
    #define MAX_THREADS 1

    int Files = 0;
    vector<string>files;


    vector<string> ListContents(string path,vector<string>&files)
    {
        HANDLE hfind = INVALID_HANDLE_VALUE;
        WIN32_FIND_DATAA ffd;
        string spec;
        wstring ws;
        deque<string> directories;

        directories.push_back(path);
        files.clear();

        while(!directories.empty())
        {
            path = directories.back();
            spec = path + "\\" + "*";
            directories.pop_back();

            std::wstring wspec( spec.begin(),spec.end());
            ws = wspec;

            hfind = FindFirstFileA(spec.c_str(),&ffd);
            if(hfind == INVALID_HANDLE_VALUE)
                continue;
                //return false;

            do
            {
                if(strcmp(ffd.cFileName,".") && strcmp(ffd.cFileName,".."))
                {
                    if(ffd.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
                    {
                        directories.push_back(path + "\\" + ffd.cFileName );
                    }
                    else
                    {
                        //cout<<"Current File is "<<ffd.cFileName<<endl;
                        files.push_back(path + "\\" + ffd.cFileName);
                        Files++;
                    }
                }
            }while(FindNextFileA(hfind,&ffd)!=0);
            if (GetLastError() != ERROR_NO_MORE_FILES) {
                FindClose(hfind);
                ExitProcess(4);
                //return false;
            }

            FindClose(hfind);
            hfind = INVALID_HANDLE_VALUE;
        }

        //return true;
        return files;
    }
    void display(vector<string>&files)
    {
        vector<string>::iterator iter = files.begin();
            if(files.size()!=0)
                do
                {
                    cout<<*iter<<endl;
                    *iter++;
                }while(iter!=files.end());

    }
    DWORD WINAPI MyThread1(LPVOID s)
    {
        char* ss = (char*)s;
        string path(ss);
        //vector<string> files;
        files = ListContents(path,files);
        //display(files);
        return 0;
    }
    int main(int argc,char *argv[])
    {
        DWORD threadid;
        int newent = 0;
        int newex = 0;
        FILETIME creation,exit,kernel,user;
        SYSTEMTIME st1,st2;
        THREADENTRY32 entry;
        char szEntrytime[255],szExittime[255];

        //vector<string> files;
         Sem = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
        for(int i= 0;i<MAX_THREADS;i++)
    {
        hthread[i] = CreateThread(NULL,0,List,NULL,0,&threadid);
         if( hthread[i] == NULL )
        {
            printf("CreateThread error: %d\n", GetLastError());
            return 1;
        }
    }

        HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);

        if(hthread)
        {
            WaitForMultipleObjects(MAX_THREADS,&hthread,TRUE,INFINITE);

             if(GetThreadTimes(hthread,&creation,&exit,&kernel,&user)==0)
             {
                 cout<<"can't able to get thrad timings";
                 ExitProcess(3);
             }
             else
             {
                 GetThreadTimes(hthread,&creation,&exit,&kernel,&user);
                 FileTimeToLocalFileTime(&creation,&creation);
                 FileTimeToLocalFileTime(&exit,&exit);
                 FileTimeToSystemTime(&creation,&st1);
                 FileTimeToSystemTime(&exit,&st2);
             }
        }

        GetTimeFormatA( LOCALE_USER_DEFAULT, 0, &st1, NULL, szEntrytime, 255 );
        GetTimeFormatA( LOCALE_USER_DEFAULT, 0, &st2, NULL, szExittime, 255 );

        printf( "Thread Entry Time %s\n", szEntrytime );
        printf( "Thread Exit Time %s\n", szExittime );


        //files = ListContents(argv[1],files);

        cout<<" No of Files  "<<Files <<endl ;
        CloseHandle(hthread);

        display(files);


        /*if(ListContents(argv[1],files))
        {

        }*/
        system("pause");
        return 0;
    }
Baalki
  • 61
  • 1
  • 6
  • A better approach would be to combine `boost::filesystem::directory_iterator` and Intel's `tbb::parallel_for_each`. – 111111 Jan 20 '14 at 10:37
  • I tried but boost filesystem is pre-included in linux alone.For Windows i need more and more dependency files.I need a solution to implement it in windows platform not for cross-platforms. – Baalki Jan 20 '14 at 10:43
  • well good luck; the windows API should be seen as a low API that shouldn't be called directly. Also in time boost.filesystem will be become std.filesystem. And you can use the MS parallel patterns lib instead of intel tbb. – 111111 Jan 20 '14 at 18:09

2 Answers2

0

The first approach that comes to my mind would be to use producer/consumer pattern where your consumers are also producers. The idea is to map listing of files in a single directory (not recursively) to a task. These tasks can be processed in parallel.

E.g. initially you have a single task - to process your given directory. When you find a subdirectory you add it to directories vector and so another thread from your pool waiting for work can take this task and process. So you need to transform you directories to producer/consumer queue and create pool of threads to process this queue. Every time you find a subdirectory add to that queue as you do right now.

The only problem is to detect when you finished your work. You can use something like a counter for waiting threads that have no work to do. When that counter reaches number of threads in your pool - post terminating items to your queue, one item per thread, that clearly indicates that thread consumed this item should terminate.

Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112
  • Thanks a lot Andy..But while goin thru this i had a doubt of how to change my directories (deque) struct to a producer/consumer struct.Am new to multithreading in c++.can u please elaborate wit a code ? – Baalki Jan 20 '14 at 11:37
  • "The following code implements a producer/consumer queue. The queue is represented as a bounded circular buffer, and is protected by a critical section. The code uses two condition variables: one used by producers (BufferNotFull) and one used by consumers (BufferNotEmpty).": http://msdn.microsoft.com/en-us/library/windows/desktop/ms686903(v=vs.85).aspx – Andriy Tylychko Jan 20 '14 at 14:22
  • i tried with the pattern u told...i call the function ListContents() from both the threads but how to make the queue as a pool of threads ??? – Baalki Jan 21 '14 at 14:35
  • I'll try to explain it in more details. First of all, find a good implementation of thread pool, or use (this one)[http://stackoverflow.com/questions/12215395/thread-pool-using-boost-asio/12267138#12267138] with Boost.Thread. As a last resort, don't bother with thread pool at all and just create bunch of threads (arbitrary number, test initially on 2 threads) with the same thread function. This function should take in loop items from your producer/consumer queue and pass to your function (modified for multithreaded processing) until special item is found (null?). – Andriy Tylychko Jan 24 '14 at 14:06
  • thanks a lot for the suggestion u gave..i here drop my alg pls crct me if any mistake – Baalki Jan 24 '14 at 18:58
0

global Queue ( consists of folders in a drive/directory ) Local Queue ( inside Thread function for Subfolders )

    while(true)
{
    lock()
    if( Global q empty)
        unlock
        break
    else
       get first folder from global q
      put it in local q
     unlock

    while(local q not empty)
        take first folder from local q
        process it
        if( folder)
           put it in local q
        else
         put it in vector ( othr purpose)
}
Baalki
  • 61
  • 1
  • 6