CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 21
  1. #1
    Join Date
    Apr 2009
    Posts
    1,355

    [RESOLVED] how make a multithread synchronization correctly?

    i'm making my own input using the richedit win32 class.
    for that i must use a structure for not lose the variable adress...
    Code:
    struct arg_readmultithread
        {
            consolewindow *consolewindowpointer=NULL;
            string *strreaded=NULL;
            char *chrreaded=NULL;
            double *dblreaded=NULL;
            string txtwrite="";
        };
    
        arg_readmultithread arg_multiread;
    
    
        void APIDoEvents()
        {
            MSG msg;
            BOOL result;
            while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE )|| blnread==true)
            {
                if(blnread==false)
                    break;
                TranslateMessage(&msg);
                if(blnread==false)
                    break;
                DispatchMessage(&msg);
                if(blnread==false)
                    break;
            }
        }
    
        pthread_t some_thread;
        pthread_mutex_t myMutex=PTHREAD_MUTEX_INITIALIZER;
        pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;
    
        void multi_read(char *chr, string *str, double *dbl)
        {
            pthread_mutex_lock(&myMutex);
            /*while(blnread==true)
            {
                if(GetInputState()==TRUE && (GetKeyState(VK_RETURN) & 0x8000) && (blnread==false))
                {
                    break;
                }
            }*/
    
            blnread=true;
    
            strreaded=str;
            dblreaded=dbl;
            ostringstream  address;
            address << strreaded;
            std:string name = address.str();
            static int i=0;
            i=i+1;
            DebugText("on function" + to_string(i) + ": "+ name);//getting the actual variable adress(debuging the code)
    
        }
    
        static void *multithreadproc(void *pThisArg)
        {
            arg_readmultithread *pThis = static_cast<arg_readmultithread*>(pThisArg);
            pThis->consolewindowpointer->multi_read(NULL,pThis->strreaded,pThis->dblreaded);
            return nullptr;//terminates the thread
        }
    
    
    
        void read(string &txttext)
        {
            //change edit control seltext color:
            CHARFORMAT2 cf ;
            cf.cbSize = sizeof( CHARFORMAT2 ) ;
            cf.dwMask = CFM_COLOR | CFM_BACKCOLOR | CFM_EFFECTS2 ;
            cf.crTextColor =clrTextColor;
            cf.dwEffects =0;
            cf.crBackColor = clrTextBackColor;
            SendMessage(consoleedit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf );
    
            //recive the variable adress:
            arg_multiread.consolewindowpointer=this;
            arg_multiread.strreaded=&txttext;
    
            //create a new thread:
            pthread_create(&some_thread, nullptr, &consolewindow::multithreadproc,static_cast<void*>(&arg_multiread));
        }
    when the return key is pressed the thread will be closed:
    Code:
    case WM_KEYUP:
                {
                    if((wParam==VK_RETURN) && (richedit->blnread==true))
                    {
                        if((is_number(richedit->readstring)==true))
                            if(richedit->dblreaded!=NULL)
                                *richedit->dblreaded=stod(richedit->readstring);
                        else
                        {
                            *richedit->dblreaded=0;
    
                        }
                        if(richedit->strreaded!=NULL)
                            *richedit->strreaded=richedit->readstring;
                        richedit->readstring="";
                        //richedit->strreaded=NULL;
                        richedit->blnread=false;
                        pthread_mutex_unlock(&richedit->myMutex);
    
    
                        //pthread_cond_signal( &richedit->condition_var );
    
                    }
                }
                break;
    the multithread is, sometimes... i repeat... sometimes, working correctly. but other times i lose the correct variable adress
    can anyone tell me what i'm doing wrong with the multithread synchronization?
    i had read several tutorials, but i continue with same problems.... 90% of code, works fine... but not always

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: how make a multithread synchronization correctly?

    When you share a resource across threads, you need to synchronize access for reading and writing in all cases.

    strreaded doesn't seem to be protected in all cases.

  3. #3
    Join Date
    Apr 2009
    Posts
    1,355

    Re: how make a multithread synchronization correctly?

    Quote Originally Posted by Arjay View Post
    When you share a resource across threads, you need to synchronize access for reading and writing in all cases.

    strreaded doesn't seem to be protected in all cases.
    now they are protected but i continue with problems
    heres the correct debug output:
    "before read: 0x28facc
    before read2: 0x28fac4
    before read3: 0x28fac0
    on function1: 0x28facc
    on function2: 0x28fac4
    on function3: 0x28fac0"

    but sometimes:
    "before read: 0x28facc
    before read2: 0x28fac4
    before read3: 0x28fac0
    on function1: 0x28fac4
    on function2: 0x28fac4
    on function3: 0x28fac0"

    why these happens?

    "When you share a resource across threads, you need to synchronize access for reading and writing in all cases."
    that's why i use:

    Code:
    pthread_mutex_lock(&myMutex);
    when i start the new thread.
    and:
    Code:
    pthread_mutex_unlock(&richedit->myMutex);
    when i release the enter key...
    but i don't understand what is wrong

  4. #4
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: how make a multithread synchronization correctly?

    You need to lock and unlock in each thread - you don't seem to be doing that.

    I find it difficult to attempt multithreading using global variables. At the very least I suggest you create a singleton class which thread safe accessors to the data you want to share (by thread safe, I mean both the getter and setter methods would each contain a pair of calls to lock/unlock).

    Another improvement is to use RAII for locking.

    Try reading some of the multithreaded articles in my signature line.

  5. #5
    Join Date
    Apr 2009
    Posts
    1,355

    Re: how make a multithread synchronization correctly?

    Quote Originally Posted by Arjay View Post
    You need to lock and unlock in each thread - you don't seem to be doing that.

    I find it difficult to attempt multithreading using global variables. At the very least I suggest you create a singleton class which thread safe accessors to the data you want to share (by thread safe, I mean both the getter and setter methods would each contain a pair of calls to lock/unlock).

    Another improvement is to use RAII for locking.

    Try reading some of the multithreaded articles in my signature line.
    using an infinite loop, i can test the keyboard input and if was the enter key. but i must let the cpu send the result(see the keyup code).
    i'm sorry, your articles are using MFC, i don't use it.

  6. #6
    Join Date
    Apr 2009
    Posts
    1,355

    Re: how make a multithread synchronization correctly?

    see these update:
    Code:
    void multi_read(char *chr, string *str, double *dbl)
        {
            pthread_mutex_lock(&myMutex);
            if (blnread==true)
                pthread_cond_wait( &condition_var, &myMutex );
    
            blnread=true;
    
            strreaded=str;
            dblreaded=dbl;
            ostringstream  address;
            address << strreaded;
            std:string name = address.str();
            static int i=0;
            i=i+1;
            DebugText("on function" + to_string(i) + ": "+ name);
            pthread_mutex_unlock(&myMutex);
            //pthread_exit(NULL);
    
        }
    when the enter key is released:
    Code:
    case WM_KEYUP:
                {
                    if((wParam==VK_RETURN) && (richedit->blnread==true))
                    {
                        if((is_number(richedit->readstring)==true))
                            if(richedit->dblreaded!=NULL)
                                *richedit->dblreaded=stod(richedit->readstring);
                        else
                        {
                            *richedit->dblreaded=0;
    
                        }
                        if(richedit->strreaded!=NULL)
                            *richedit->strreaded=richedit->readstring;
                        richedit->readstring="";
                        //richedit->strreaded=NULL;
                        richedit->blnread=false;
                        //pthread_mutex_unlock(&richedit->myMutex);
                        pthread_cond_signal( &richedit->condition_var );
                    }
                }
                break;
    but sometimes, again :
    "before read: 0x28facc
    before read2: 0x28fac4
    before read3: 0x28fac0
    on function1: 0x28facc
    on function2: 0x28fac0
    on function3: 0x28fac0"

    i'm reading: http://codebase.eu/tutorial/posix-th...tion_variables (multithread tutorial)
    but, by some reason, i can't use the pthread_join(), because freezes the application\form... or i'm, too, confused how i can use it too

  7. #7
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: how make a multithread synchronization correctly?

    Quote Originally Posted by Cambalinho View Post
    i'm sorry, your articles are using MFC, i don't use it.
    Yes, they use MFC but not for the threading concepts. You are having trouble because you don't understand the basics of thread synchronization. Working through my articles, in spite of the MFC probably would help you.

  8. #8
    Join Date
    Apr 2009
    Posts
    1,355

    Re: how make a multithread synchronization correctly?

    Quote Originally Posted by Arjay View Post
    Yes, they use MFC but not for the threading concepts. You are having trouble because you don't understand the basics of thread synchronization. Working through my articles, in spite of the MFC probably would help you.
    i'm so sorry.. don't be mad with me, but can you tell me what is confuse me on code, please?
    the code seems fine from what i readed

  9. #9
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: how make a multithread synchronization correctly?

    See the SimpleThread article - that is a simple console app that doesn't use MFC. Trying to create a thread safe app using global variables is difficult and the hard way to do it (no wonder why folks that take this approach find multi-threading so hard).

    At any rate, the issue with your code is that the richedit control can access the data at any time and you aren't protecting that data. You protect it in the worker thread, but don't protected it when access from the UI thread that has the richedit control. Since you are using globals, I can't offer any suggestions on fixing your code.

  10. #10
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: how make a multithread synchronization correctly?

    In multi-threaded code, you need to protect shared variables from being accessed/updated whilst they are being modified. This can be done using a mutex. In every case use of these shared variables is protected by using a mutex lock. The code that manipulates the shared variables is protected by use of a mutex lock - but every case of usage - whether read or modify - must be protected so that across multiple threads access to the shared variables is serialised. In your WM_KEYUP code I don't see that access to the shared variables is protected by the mutex?

    PS Why are you using Posix pthreads for a c++11 WIN32 program? Why not use c++11 in-built multi-threading? or use the standard WIN32 multi-threading API's.

    See
    http://www.cplusplus.com/reference/multithreading/
    https://msdn.microsoft.com/en-US/library/y6h8hye8.aspx
    Last edited by 2kaud; December 20th, 2015 at 06:59 AM. Reason: PS
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  11. #11

    Re: how make a multithread synchronization correctly?

    i found the problem. how i resolve it: asynchronous the Read() function. but the next lines was not executed, because the Read() isn't a new thread. let me ask: imagine that 1 variable string have a value of 1 adress. can i use that value and convert it to LPVOID?
    Last edited by bestellen; June 4th, 2016 at 04:14 PM.

  12. #12
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: how make a multithread synchronization correctly?

    Quote Originally Posted by bestellen View Post
    i found the problem. how i resolve it: asynchronous the Read() function. but the next lines was not executed, because the Read() isn't a new thread. let me ask: imagine that 1 variable string have a value of 1 adress. can i use that value and convert it to LPVOID?
    Why are you responding to this thread? If you have a question, start a new thread?

  13. #13
    Join Date
    Apr 2009
    Posts
    1,355

    Re: how make a multithread synchronization correctly?

    i was getting several problems for make a shyncronization multithread. so, finally, i finish my own multithread class:
    Code:
    class Multithread
    {
    private:
        HANDLE hThread=NULL;
        DWORD dwThreadId=0;
        bool blnSingleThreadAtTime=false;
        bool blnCreationOrder=true;
        function<void()> multithreadfunction=NULL;
        function<void(LPVOID param)> multithreadparameterfunction=NULL;
        HANDLE myEvent = CreateEvent(0, 0, 0, 0);
    
        struct mytread
        {
            Multithread *classpointer=NULL;
            LPVOID multithreadparameters=NULL;
        };
        vector<mytread> mtparameterthread;
    
    public:
    
        void SingleThreadAtTime(bool SingleThread)
        {
            blnSingleThreadAtTime=SingleThread;
        }
    
        bool SingleThreadAtTime()
        {
            return blnSingleThreadAtTime;
        }
        
        //make the threads by creation order
        void CreationOrder(bool OrderCreation)
        {
            blnCreationOrder=OrderCreation;
        }
    
        bool CreationOrder()
        {
            return blnCreationOrder;
        }
    
        void WaitCondition()
        {
            WaitForSingleObject(myEvent, INFINITE);
        }
    
        void SetCondition()
        {
            SetEvent(myEvent);
        }
    
        static DWORD WINAPI MyThreadFunction( LPVOID lpParam )
        {
            static bool blnfirsttime=false;
            Multithread *pThis = static_cast<Multithread*>(lpParam);
            if(pThis->blnSingleThreadAtTime==true && blnfirsttime==true)
                pThis->WaitCondition();
            blnfirsttime=true;
            pThis->multithreadfunction();
            if(pThis->blnSingleThreadAtTime==true && blnfirsttime==true)
                pThis->SetCondition();
    
            return 0;
        }
    
        static DWORD WINAPI MyParameterThreadFunction( LPVOID lpParam )
        {
            static bool blnfirsttime=false;
            mytread *pThis = static_cast<mytread*>(lpParam);
            if(pThis->classpointer->blnSingleThreadAtTime==true && blnfirsttime==true)
                pThis->classpointer->WaitCondition();
            blnfirsttime=true;
            pThis->classpointer->multithreadparameterfunction(pThis->multithreadparameters);
            if(pThis->classpointer->blnSingleThreadAtTime==true && blnfirsttime==true)
                pThis->classpointer->SetCondition();
            return 0;
        }
    
        Multithread(std::function<void()> SetFunction)
        {
            mtparameterthread.reserve(100);
            multithreadfunction=SetFunction;
        }
    
        Multithread( function<void(LPVOID)> SetFunction )
        {
            mtparameterthread.reserve(100);
            multithreadparameterfunction =SetFunction;
        }
    
        //corrigir
        template<typename tpVariant>
        Multithread( function<void(tpVariant)> SetFunction )
        {
            mtparameterthread.reserve(100);
            multithreadparameterfunction = [=]( LPVOID pv ) { SetFunction( static_cast<tpVariant>( pv ) ); };
        }
    
        int i=-1;
        template<typename tpVariant>
        void operator ()(tpVariant &vrParam)
        {
            //LPVOID lpParam=static_cast<LPVOID>(&vrParam);
            i=i+1;
            mtparameterthread[i].classpointer = this;
            mtparameterthread[i].multithreadparameters = &vrParam;
    
            hThread= CreateThread(
                NULL,                   // default security attributes
                0,                      // use default stack size
                &Multithread::MyParameterThreadFunction,       // thread function name
                &mtparameterthread[i],          // argument to thread function
                0,                      // use default creation flags
                &dwThreadId);
            if(i==100)
                i=-1;
            if(blnCreationOrder==true)
                delay(100);
        }
    
        void operator ()(LPVOID vrParam)
        {
            i=i+1;
            mtparameterthread[i].classpointer = this;
            mtparameterthread[i].multithreadparameters = vrParam;
    
            hThread= CreateThread(
                NULL,                   // default security attributes
                0,                      // use default stack size
                &Multithread::MyParameterThreadFunction,       // thread function name
                &mtparameterthread[i],          // argument to thread function
                0,                      // use default creation flags
                &dwThreadId);
            if(i==100)
                i=-1;
            //delay for avoiding execution of all threads in same time and for not losing data because of that
            if(blnCreationOrder==true)
                delay(100);
    
        }
    
        void operator ()()
        {
           hThread  = CreateThread(
                NULL,                   // default security attributes
                0,                      // use default stack size
                &Multithread::MyThreadFunction,       // thread function name
                this,          // argument to thread function
                0,                      // use default creation flags
                &dwThreadId);
            if(blnCreationOrder==true)
                delay(100);
        }
    
        ~Multithread()
        {
            CloseHandle(hThread);
            CloseHandle(myEvent);
        }
    };
    - i use a delay(sleep()) for garantie that the threads are create in same order that i create them;
    - i let the wait conditions for be more flexible on any situation;
    - i use a vector for never lose the data;
    - i overload 3 time the function operator for accept no arguments, LPVOID and other types.



    heres how i use it on read():

    Code:
    struct strucread
        {
            LPVOID varadress=NULL; //for get the variable adress
            string vartype=""; //for get what type is 
            variant varvalue=""; //these is for write()... i had created the variant type too
        };
        vector<strucread> readdata;
    
        //these constructor function works fine for a string, but not for a numbers or char* :(
         Multithread mtRead{ [&]( LPVOID varname)
        {
            strucread *strTest=static_cast<strucread*>(varname);
            if(strTest->vartype!="write")//for write().. these is for make the write been by read order dependency
                blnread=true;
            while(blnread==true)
            {
                MSG TMsg;
                do
                {
                    if(blnread==false)
                        break;
                    TranslateMessage(&TMsg);
                    if(blnread==false)
                        break;
                    DispatchMessage(&TMsg);
                    if(blnread==false)
                        break;
                }
                while (PeekMessage(&TMsg, 0, 0, 0, true) || (blnread==true));
            }
            if(strTest->vartype=="string")//read(string)
                *((string*)(strTest->varadress)) = readstring;
            else if(strTest->vartype=="char*")
            {
                char *cstr = new char[readstring.length() + 1];
                strcpy(cstr, readstring.c_str());
                *((char*)(strTest->varadress)) =cstr[0];
                delete [] cstr;
            }
            else if(strTest->vartype=="char")
            {
                char cstr = readstring[0];
                *((char*)(strTest->varadress)) =cstr;
            }
            else if(strTest->vartype=="double")
            {
                if(is_number(readstring)==true)
                {
                    *((double*)(strTest->varadress)) = stof(readstring);
                }
                else
                {
                    *((double*)(strTest->varadress)) =0;
                }
            }
            else if(strTest->vartype=="int")
            {
                if(is_number(readstring)==true)
                {
                    *((int*)(strTest->varadress)) = stoi(readstring);
                }
                else
                {
                    *((int*)(strTest->varadress)) =0;
                }
            }
            else if(strTest->vartype=="variant")
                *((variant*)(strTest->varadress)) = readstring;
            else if(strTest->vartype=="write")
            {
                CHARRANGE cr;
                cr.cpMin = -1;
                cr.cpMax = -1;
                SendMessage(consoleedit, EM_EXSETSEL, 0, (LPARAM)&cr);
                string strValue=strTest->varvalue;
                SendMessage(consoleedit, EM_REPLACESEL, 0, (LPARAM)(char*)strTest->varvalue);
            }
            readstring="";
        }};
    
    
    void read(string &txttext)
        {
            //alterar o formato e a cor de texto
            CHARFORMAT2 cf ;
            cf.cbSize = sizeof( CHARFORMAT2 ) ;
            cf.dwMask = CFM_COLOR | CFM_BACKCOLOR | CFM_EFFECTS2 ;
            cf.crTextColor =clrTextColor;
            cf.dwEffects =0;
            cf.crBackColor = clrTextBackColor;
            SendMessage(consoleedit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf );
            i=i+1;
            readdata[i].varadress=&txttext;
            readdata[i].vartype="string";
            mtRead(&readdata[i]);
            if(i==100)
                i=-1;
        }
    - i used an array vector for not lose the data. the 100 is number of elements for the vector.

    heres on write():
    Code:
    void write(variant strText)
        {
            i=i+1;
            readdata[i].vartype="write";
            readdata[i].varvalue=strText;
            mtRead(&readdata[i]);
            if(i==100)
                i=-1;
        }
    i'm using the variant type, but it's ony for show how i use it.
    i hope that my class helps the others like is help me.
    sorry something and thanks to all

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

    Re: [RESOLVED] how make a multithread synchronization correctly?

    Unsynchronized Access/Race Condition on lines:
    54,56,58,60
    68,70,72,74
    104,115,116
    123,134,135

    >> i use a delay(sleep()) for garantie ...
    That is far from any type of garantie.

    You are trying to do too much in one class - separate out the concerns. If you want a simple C++ wrapper to the CreateThread() C interface, then do only that.

    gg

  15. #15
    Join Date
    Apr 2009
    Posts
    1,355

    Re: [RESOLVED] how make a multithread synchronization correctly?

    Quote Originally Posted by Codeplug View Post
    Unsynchronized Access/Race Condition on lines:
    54,56,58,60
    68,70,72,74
    104,115,116
    123,134,135

    >> i use a delay(sleep()) for garantie ...
    That is far from any type of garantie.

    You are trying to do too much in one class - separate out the concerns. If you want a simple C++ wrapper to the CreateThread() C interface, then do only that.

    gg
    sorry... on your test do you use SingleThreadAtTime(true)? yes these make sure that waits until the last thread is finished

Page 1 of 2 12 LastLast

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