CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    Jul 2008
    Posts
    15

    Question Using Multithreading to encrypt a file

    My problem sounds like this:

    I have to create a program that encrypts a file by taking each byte and increment it.
    The problem is that the program should use multithreading to do the actual encrypting. The number of threads is variable, the user enters them in a Edit Control, and those “x” number of threads, simultaneously must encrypt the file.

    What I’ve done so far is that I opened the file in binary mode and encrypt it by incrementing each byte in the file. So far so good, but now I can’t figure out how to create those threads and how should they encrypt the file simultaneously … a little help would be awesome.

    Here is the code I done so far: when the user pushes the Ok button (the file has been selected by the user in a previous step), the selected file is encrypted

    Code:
    void CEncryptorView::OnBnClickedOk()
    { 
      	CString strControlText;    
    	CWnd* pWnd = GetDlgItem(IDC_FILE);
    	pWnd->GetWindowText(_T(strControlText));  
    
    	char buf[255];
    	
    	//open the selected file for encryption
    	ifstream fp_in(strControlText, ios_base::binary | ios_base::in);
    
    	unsigned int cntr = 0; //defining a controll variable;
    	if(!fp_in)
    	{
    		++cntr;
    		MessageBox("The selected file couldn't be open for reading");
    	}
    	ofstream fp_out("temp.txt",	ios_base::binary | ios_base::out);
    	if(!fp_out)
    	{
    		++cntr;
    		MessageBox("\tThe temp file couldn't be created \n(check you access privileges for default destination!)");
    	}
    
    	//encrypting the file, taking each byte in the file and increment it
    	if ( fp_in && fp_out )
    	{
    		char ch;
    		while ( fp_in.get ( ch ) )
    		  fp_out.put ( ++ch );
    	}
    	else
    		++cntr;
    
    	fp_in.close();
    	fp_in.clear();
    	fp_out.close();
    	fp_out.clear();
    
    	//copying (replacing) the encrypted temp file into the original file, and deleting the tempoarary one
    	ifstream fs_in("temp.txt", ios_base::binary | ios_base::in);
    	if(!fs_in)
    	{
    		++cntr;
    		MessageBox("An error occured and the encryption failed");
    	}
    	ofstream fs_out(strControlText,	ios_base::binary | ios_base::out);
    	if(!fs_out)
    	{
    		++cntr;
    		MessageBox("An error occured and the encryption failed");
    	}
    
    	if ( fs_in && fs_out )
    	{
    		char ch;
    		while ( fs_in.get ( ch ) )
    		  fs_out.put ( ch );
    	}
    	else
    		++cntr;
    
    	fs_in.close();
    	fs_in.clear();
    	fs_out.close();
    	fs_out.clear();
    
    	//delete the temp file
    	CString fileToDelete("temp.txt");
    	if(remove(fileToDelete) == 0 && cntr == 0)
    		MessageBox("The file has ben encrypted successfully");
    	else
    		MessageBox("An error occured and the encryption failed");
    }
    Thank you!

  2. #2
    Join Date
    Nov 2006
    Posts
    1,611

    Re: Using Multithreading to encrypt a file

    Homework?

    Have you looked up CreateThread, beginthread and similar?

    The plan for dividing the job is curious. What is the nature of the data? Text files only I assume? Typical file sizes?

    You can divide the file into equal sections and 'schedule' each thread to encrypt a portion of the file. This won't be a performance enhancement on large files that exceed the cache, and write performance might be abysmal, but it would, perhaps, suffice as an exercise.


    Is the nature of the threading just an exercise or is there some expectation of performance improvement?
    If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).

  3. #3
    Join Date
    Jul 2008
    Posts
    15

    Re: Using Multithreading to encrypt a file

    It’s an exercise (and I have to finish it in a couple of hours ), so the performance improvement is not the most important thing.

    The nature of the data is not specified, by I restricted the files to text files only (the user can open only the files with .txt and .csv extension). The file sizes are typical.

    How should I divide the files? By getting the size (in bytes) of the file and divide it to the number of threads specified in the Edit Control box? If so, the number of threads has to be smaller than the size of the file. But the number of threads is variable, the user selects it in a control box on the form, how can I dynamically create threads?

    The algorithm of encoding the files using multi-threads is a bit weird to me, I must admit that I never worked with threads before so this might be the reason.

  4. #4
    Join Date
    Nov 2006
    Posts
    1,611

    Re: Using Multithreading to encrypt a file

    I must admit that I never worked with threads before so this might be the reason.
    And I think your few hours are up. Because of the above, I don't believe you're going to get it working in time. I believe this is one reason self study is so powerful - you can work a problem until you understand it, instead of cramming toward a deadline (though I understand that value of THAT exercise).

    You can't just launch thousands of threads - so the number of threads you can accept from the user must be limited to some reasonable value. The number of cores is one way to think of it (parallel processing of more than the available cores is of limited value, even though it functions).

    Of course, in an exercise, using even 10 times the threads as cores available is fine.

    Use beginthread or CreateThread to launch a thread. That requires a thread function, and takes a parameter. Pass the pointer to a structure that describes some small amount of the file to process.

    In the thread function, keep in mind that every thread will run the same function - so it must be capable of operating on local (stack) data, and the structure that was passed to it - no globals.

    You had it right - you can divide the file into equal parts. Obviously care must be taken to avoid something silly like accepting 20 threads for a files thats only 40 bytes long - it's silly to launch 20 thread to process 2 bytes each, but exercises can be silly sometimes.

    Each 'chunk' will have it's on start/end position to process. Within that context, your program functions fairly close to the existing loop (I'm assuming much here, I've not read with great detail on your code, sorry).

    Frankly, for a first time thread project, I'd say you need a full day or two to get it right.

    You should probably have done something simpler with threads first, like launch 10 threads that count - watch it work within a debugger (which is maddening sometimes, you'll understand when you see it).
    If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).

  5. #5
    Join Date
    Jul 2008
    Posts
    15

    Re: Using Multithreading to encrypt a file

    Thanks JVene for the walktrough, i know that i should've start with some simpler threads first but only this evening i got this application, and i have a deadline till tomorrow, so i haven't got time to study the threads.

    I am currently followind an example from http://msdn.microsoft.com/en-us/library/ms682516.aspx
    wich kinda follows the steps you suggested, and i'm starting to understand the problem better and better.

    Can you give me an approximate example on how my structure that should process a small amount of the file should look like? How can i only open the file and only process x bytes of it?

    I have so many questions...

  6. #6
    Join Date
    Jan 2006
    Location
    Fox Lake, IL
    Posts
    15,007

    Re: Using Multithreading to encrypt a file

    You have to enqueue the threads with 1) their task 2) data so after you seperate the file into chunks, pass it to a thread with some way to keep track of it's order (i'll leave that up to you)

    1 is already done, so apply this to the samples and post again. The forum is 24x7
    David

    CodeGuru Article: Bound Controls are Evil-VB6
    2013 Samples: MS CODE Samples

    CodeGuru Reviewer
    2006 Dell CSP
    2006, 2007 & 2008 MVP Visual Basic
    If your question has been answered satisfactorily, and it has been helpful, then, please, Rate this Post!

  7. #7
    Join Date
    Nov 2006
    Posts
    1,611

    Re: Using Multithreading to encrypt a file

    Well, first you have to get the file's size. Let's say it's 1000 bytes for simplicity.

    Now you can determine the max reasonable threads at your option. Let's say you insist on handling at least 100 bytes per thread, so at max you'd accept 10 threads here.

    So, you create 10 thread 'scheduler' objects, each holding two longs (or whatever you like - uint64 would do if you're handling large files.

    As you loop 10 times to create threads, you'll create a scheduler object and supply a startposition and length for processing. The first entry will have a startposition of zero, length of filelength / numthreads.

    After each new thread, increment startposition by length, and keep a running sum of the total amount scheduled.

    For the last entry to schedule, make sure you set THAT length to the amount left in the file (the division may have truncated some, so that last entry may not be exactly 100 bytes if, say, the file's real size were 995 or 1005 bytes long).

    Each thread is going to seek the input at it's startposition and read bytes (or however you like to block the input).

    Set the output file to the startposition (seekp).

    Process length bytes and stop.
    If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).

  8. #8
    Join Date
    Jul 2008
    Posts
    15

    Re: Using Multithreading to encrypt a file

    A big problem is that the nuber of threads is allocated dinamicly, the number is not known untill runtime. how do i solve this? I was thinking of a vector<> of threads, but i couldn't find anything about them on them on the internet. Is it even possible to create a vector of threads, taking count that a vector is copiable but not movable and a thread is only movable?

  9. #9
    Join Date
    May 2007
    Posts
    811

    Re: Using Multithreading to encrypt a file

    Almost in boost threadpool might be of some use.

  10. #10
    Join Date
    Nov 2006
    Posts
    1,611

    Re: Using Multithreading to encrypt a file

    You're on the right track.

    In my own work I have a library that supports threaded development (I've written about it now and then around here). One object, called a QueProcessor, creates a thread for me.

    QueProcessor q1;

    ...at this point a thread has been created, and I can submit work to it with something like...

    q1.Submit( &somefunction );

    or

    q1.Submit( o, &object::somememberfunction );

    and others....


    I also have a threadpool object, representing a collection of threads dynamically created on demand. The idea there is the pool represents the execution of a function for offloading (to avoid blocking the GUI thread), and multiple calls may be of undetermined duration. The pool waits for a small amount of time, in case an existing thread finishes soon, and if the time expires, the pool launches a new thread and dispatches the work.

    These object aren't copyable, but I can store them via a shared_ptr. If you don't use shared_ptr in your work, it can be managed by a simple class that enforces that, upon a copy, the source object null's it's pointer to a thread object without deleting (so only one object holds a pointer to a thread).

    In any event, while you can put an object that can't be copied into a vector, you can put pointers to such objects in a vector, you just have to handle the issue of containment (deleting the thread object appropriately - shared_ptr solves that easily).
    If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).

  11. #11
    Join Date
    Jul 2008
    Posts
    15

    Re: Using Multithreading to encrypt a file

    god dammit... this is starting to become too difficult for my experience level...

  12. #12
    Join Date
    Nov 2006
    Posts
    1,611

    Re: Using Multithreading to encrypt a file

    i know that i should've start with some simpler threads first but only this evening i got this application, and i have a deadline till tomorrow, so i haven't got time to study the threads.
    When you have some time, I'd like to learn how you got into that situation.

    I think what you're going to learn from this is less about threads and more about the paradox of the quote above.

    I empathize. Threads aren't really all that difficult once you get used to them, but at first attempt(s) people do find the aggregate complexities rather daunting. At some point, a few months from now, when this frustration has (hopefully) turned into drive to figure this out so it's behind you, you'll look back and think it was a simple task you could have solved in an hour - but that's what hindsight is like.


    Can you post code progress?

    Best of luck....
    If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).

  13. #13
    Join Date
    Jul 2008
    Posts
    15

    Post Re: Using Multithreading to encrypt a file

    Sorry for the late answer, i was out of town this weekend.

    Quote Originally Posted by JVene View Post
    When you have some time, I'd like to learn how you got into that situation.

    Can you post code progress?

    I'm doing a Masters Degree in Informatical Systems. One of my teachers of which i missed a lot of classes, gave me an assignment of 3 small project (2 in VC++ and one in C#). I had to complete those project in a couple of days, in order for him to let me take the exam. One of those projects was this one, the other two i solved in time. So this is how I got into this unpleasant situation

    Although I already sent him the project half finished, I am still curious how to solve the multithreading problem. So I am still in need of some help.

    I'll post the code progress so far:

    I constructed a testing thread to understand how it works, like this: (I’m not sure if it's ok)
    I tried to read the file first using multithreading.

    Code:
    DWORD WINAPI mythread(LPVOID param)
    {
        int i = (int) param;
        BYTE buf[1000];
        DWORD numread;
    
        HANDLE h = CreateFile("d:\\test.txt", GENERIC_READ, FILE_SHARE_READ,
            NULL, OPEN_EXISTING, 0, NULL);
    
        SetFilePointer(h, i * 1000, NULL, FILE_BEGIN);
        ReadFile(h, buf, sizeof(buf), &numread, NULL); 
    
    }

    Now I put this other part where I create the threads in an OnBnClick event handler

    Code:
    int i;
    	const int nr_threads = GetDlgItemInt(IDC_NRTHRDS);  //getting the number of threads requested by the user, from an Edit Control
    	
        HANDLE h[nr_threads];
    
        for (i = 0; i < nr_threads; i++)
            h[nr_threads] = CreateThread(NULL, 0, mythread, (LPVOID)i, 0, NULL);
    
        for (i = 0; i < nr_threads; i++)
    		WaitForMultipleObjects(4, h, TRUE, INFINITE);
    The HANDLE h[nr_threads] is not working because I need a constant value there. And how can I assign a constant value if I get the value only at run-time?

    I don't know if this is ok (the way I’m creating the threads), but I did the best I could.

    How do I integrate the encryption algorithm into this thread?

    the code for the encryption algorithm is the following:

    Code:
    //getting the path of the file to encode from the selected file
    CString strControlText;    
    	CWnd* pWnd = GetDlgItem(IDC_FILE);
    	pWnd->GetWindowText(_T(strControlText));
    
    //open the selected file for encryption
    	ifstream fp_in(strControlText, ios_base::binary | ios_base::in);
    ofstream fp_out("temp.txt",	ios_base::binary | ios_base::out);
    
    //encrypting the file, taking each byte in the file and incrementing it
    
    	if ( fp_in && fp_out )
    	{
    		char ch;
    		while ( fp_in.get ( ch ) )
    		  fp_out.put ( ++ch );
    	}
    I left out the part where I check if the file streams are opened correctly and where the original file is replaced with the temporary encoded one, to make the code more readable.
    Last edited by Sh_oK; May 25th, 2009 at 07:17 PM.

  14. #14
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Using Multithreading to encrypt a file

    >> HANDLE h[nr_threads] is not working because I need a constant value
    You could use a vector<HANDLE>, allocate off the heap directly, or even allocate off the stack.

    >> WaitForMultipleObjects(4, h ...
    Remove the for loop and wait for all 'nr_threads' at once - or keep the for loop and use WaitForSingleObject.

    Check for error conditions on all function/methods.

    >> I don't know if this is ok (the way I’m creating the threads)
    Your call to CreateThread looks good. However, in an MFC application you typically use AfxBeginThread for thread creation. It's not absolutely necessary if the the thread function has nothing to do with MFC. Another "however" is that if your function uses the CRT at all, you should use _beginthreadex for thread creation.

    >> _T(strControlText)
    You only use the _T macro on string literals. My advice is to forget that TCHAR's and _T() even exist. Either code straight ANSI or straight Unicode ... in my opinion.

    >> How do I integrate the encryption algorithm into this thread?
    The easy thing to do is to create a buffer that is the size of the file to convert. Then the main thread would be the primary file-reader. The main loop would be something like:
    Code:
    For each 1000 byte block (or partial last block)
        Read block from file into file buffer
        Start a thread to process that block
    End For
    So each thread created will need the following information:
    - buffer of file contents
    - start offset into buffer
    - size of block to process
    Passing a pointer to a structure through the 'LPVOID param' is typical.

    When all threads are finished, simply write the processed file buffer back out to disk.

    gg

  15. #15
    Join Date
    Nov 2006
    Posts
    1,611

    Re: Using Multithreading to encrypt a file

    I have to admit, I'm a little rusty on win32 API for threads. Long ago, when OS/2 was new and NT didn't yet exist, I developed classes to do all of this, and updated them as the years went by. Generally I don't have to think much about threading, it's been reduced to a trivial act for any of the OS I target.

    Codeplug has already covered the answers to your questions.

    I'm going to suggest a few C++ ideas for helping make this a little easier.

    Somewhere around here a member (sorry, I forget the name) has a few good articles on these concepts, too.

    I'd suggest a thread object. A class that represents a thread. A simple version can start the thread and execute a virtual "do" function as the thread's function. You can then derive from the thread class and supply your own function.

    To make that work, you need a function "InitiateThread" or some such non-member function defined thus:

    UINT __cdecl InitiateThread( LPVOID param );

    Or something similar and compatible with whatever your thread call requires, be it _beginthread, AfxBeginThread or whatever (mine has versions for various operating systems where this function signature differs for each situation).

    In the thread class' StartThread function (which can be called inside the constructor, or you can decide you want to explicitly call it in application code ), you do something like:

    ThreadId = _beginthread( InitiateThread, 0, (void *)this );

    ThreadId is a member of the thread class, this line is inside the StartThread member function. It creates a thread that starts out calling the non-member InitiateThread function, passing "this" as data.

    The initiatethread function looks something like this (mine is complicated, has conditional code for various operating systems, this is pseudo code)

    Code:
    UINT __cdecl InitiateThread( LPVOID param ) // whatever signature your version requires
    {
     ThreadBase *tbp = reinterpret_cast<ThreadBase *>( param );
    
     tbp->Run(); 
    
     return 0;
    }
    In my own, I wrap the call to tbp->Run inside a try/catch block to handle exceptions. There may be "pthread_exit(NULL)" or other cleanup to perform when the Run function returns (pthread_exit is for Linux).

    The point is that "Run" is a virtual function in ThreadBase - likely a pure virtual function - which now runs your member function of the class you derive from ThreadBase.

    You can now create a collection of ThreadBase objects by pointer.

    I have classes that either derive from ThreadBase or own a ThreadBase (or ThreadBase derivative), which support threaded development of a wide variety of situations, including my most used thread class - QueProcessor. The Que owns a ThreadBase, starts it, and runs it's own processing loop. That loop waits on an event (which I'll mention in a moment). The Que accepts submissions using an object that represents "pointer to member function" or "functor" objects, allowing statements like:

    QueProcessor q1; // a thread is now running here.....

    q1.Submit( anobject, &MyObject::MemberFunction );

    After that call, the thread owned by q1 is now executing MemberFunction on the object "anobject". Obviously, I know anobject will survive long enough for that to occur, but other versions of Submit allow me to pass a template which "owns" a copy of "anobject" and uses it - lots of variations that suit each purpose I've come across over the years.


    Now, I suggest an AutoResetEvent class.

    This automatically creates (and subsequently closes the handle to) an OS event object. I use the main "create" call as:

    CreateEvent( NULL, false, false, NULL );

    The return handle is owned by the AutoResetEvent.

    Two member functions serve the event.

    bool Signal() { ::SetEvent( EventHandle ); }

    and

    bool Wait( unsigned int n ) { return WaitForSingleObject( EventHandle, n ) == WAIT_FAILED;


    I suggest inlines.

    Now, AutoResetEvent can be a member of just about anything, and I can....


    AutoResetEvent e;

    e.Wait();


    ..and elsewhere...

    e.Signal();

    Rather simpler than the win32 interface.


    You only need one event, and a means of knowing when all scheduled threads are completed.

    A crude example...

    Code:
    while( threadsfinished < threadsscheduled )
       {
         e.Wait();
       }
    As each thread finishes it would lock, increment, and release the integer "threadsfinished", then signal e with

    e.Signal();


    This way, the loop waits, but checks (quickly) as threads finish.

    In other words, you're not waiting on 4 events. You're waiting on one event all threads signal, and checking on their status.

    To wait on 4 events, you'd have to use "WaitForMultipleObjects" - I'll leave the research on it to you.

    Frankly, this loop is better, but you might want a "dead/locked thread" provision, or it hangs.

    You could also use "joinable" threads, but that's a different topic, same idea.

    You may also want a "CriticalSync" kind of object - or a Mutex object.

    This "Sync" creates a critical section in Windows. It represents the "synchronizer" object for a resource to be protected (like that integer threadsfinished).

    Then, you'll want a lock object. It calls "EnterCriticalSection" upon construction and "LeaveCriticalSection" upon exit....thus:

    Code:
    void someobject::IncrementCount()
    {
     Lock( threadcountsync );
    
     ++threadsfinished;
    }
    Assuming "CriticalSync threadcountsync" is in scope already, this locks the sync, increments the protected integer, and releases the sync.

    There are lots of other approaches.

    My point is, you can use the leverage of objects to organize the threading work, starting your own portable library of solutions to threading that eventually make threading trivial.

    Your plan is sound, given these few suggestions.

    If I were using my own library for this, I'd do something like this in application code:

    Code:
    JoinedThreadGroup j;
    int startpos = 0;
    int length = 100; // or whatever value
    int totallength = 1000; // or whatever value;
    int threadstostart = totallength / length; // sort of
    
    for( int n=0; n < threadstostart; ++n ) 
    { 
       j.Submit( this, &Encryptor::encrypt, startpos, length );
       startpos += length;
    }
    
    j.Wait();
    I'm jotting this pseudo code down without a care in the world about the startpos/length/totallength relationship to the number of threads, so I might be scheduling too many or not enough here.

    The point is, I'd create a JoinedThreadGoup, stuff a set of jobs into it using two parameters, then wait on the threadgroup to signal it's done.

    Slight variations on ThreadGroup allows for dynamic creation of threads on demand, resetting of the group when the current task is done (preserving the threadgroup for re-use), keeping the threads around and waiting (for a sequence of jobs - so I'm reusing threads from a pool, not re-launching them all the time), and lots more.

    All inside objects such that I don't have to work so hard at it anymore.

    Solve the problem, keep the solution (generalize it) - build a library.
    Last edited by JVene; May 27th, 2009 at 02:24 PM.
    If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured