how make a multithread correctly synchronizated?

how can i make a multithread, correctly, synchronition?

for make a multtihread function i must do use:
pthread_create()
using mutex i can synchronizate(saying the tutorials).
so heres the code using multithread with parameters:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  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 ))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    pthread_t some_thread;
    pthread_mutex_t myMutex;

    void multi_read(char *chr, string *str, double *dbl)
    {
        pthread_mutex_lock(&myMutex);//starts the synchronization multithread
        while(blnread==true)
        {
            APIDoEvents();
        }

        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);
    }

    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.. it's void*
    }



    void read(string &txttext)
    {
        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 );
        arg_multiread.consolewindowpointer=this;
        arg_multiread.strreaded=&txttext;
        pthread_create(&some_thread, nullptr, &consolewindow::multithreadproc,static_cast<void*>(&arg_multiread));
    }

//and when the enter key is pressed:
case WM_KEYUP:
            {
                if((wParam==VK_RETURN) && (richedit->blnread==true))
                {
                    richedit->blnread=false;
                    if((is_number(richedit->readstring)==true))
                        if(richedit->dblreaded!=NULL)
                            *richedit->dblreaded=stod(richedit->readstring);
                    else
                    {
                        *richedit->dblreaded=0;

                    }
                    if(richedit->strreaded!=NULL) //richedit it's a richedit instance pointer object 
                        *richedit->strreaded=richedit->readstring;
                    richedit->readstring="";
                    richedit->strreaded=NULL;
                    pthread_mutex_unlock(&richedit->myMutex);//terminates the thread
                }
            }
            break;

heres the correct 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"

why the synchronization isn't 100%? :(
For this you need to understand exactly what a mutex is. I'll try to explain by comparing it to a door.

Say you have for example one door, of which there exists one key. To go through the door, you must take the key, unlock the door and go in, only when you come back out you can put the key back and the next person can go in. That way only one person can ever go through the door at once. The key doesn't care about what person goes first, it only makes sure that one person goes through the door at once.

A mutex works comparable. A thread can lock the mutex (comparable to taking the key and going trough the door). When the next thread tries to take the mutex before the other thread unlocks it, it will block until the other thread unlocks the mutex (comes out of the door and puts the key back). But there's no guarantee on what thread will lock the mutex first.

So in your example, you can't tell which thread (1, 2 or 3) will enter the code first, you just know only one thread will execute the code at once. Sometimes the thread using address 0x28fac4 will be first, sometimes the thread using 0x28fac0 will go first, and sometimes the thread using 0x28facc will go first.

Note that this usually isn't a problem. The only reason you will be using a mutex for will be to ensure that some code that does something that should not be done with multiple threads at once will only be used by one thread at once. The order should not be important, otherwise you wouldn't be using threads in the first place. Why use a thread when you want code to execute in a specific order? (Note that this doesn't apply everywhere, but let's ignore corner cases here).
Last edited on
using mutex, again, on read(), i will garantie the thread order. but i will get problems because the read() isn't multithread :(
so i came up with 1 idea, that maybe will help me. imagine that i have 1 string and the string value is 1 variable adress. can i convert that value to a adress for the LPVOID accept it?
fixed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#define delay(x) _sleep(x)
class Multithread
{
private:
    HANDLE hThread=NULL;
    DWORD dwThreadId=0;
    bool blnSingleThreadAtTime=false;
    bool blnCreationOrder=true;
    function<void()> multithreadfunction=NULL;
    function<void(const 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;
    }
 
    void CreationOrder(bool OrderCreation)
    {
        blnCreationOrder=OrderCreation;
    }
 
    bool CreationOrder()
    {
        return blnCreationOrder;
    }
 
    void WaitCondition()
    {
        WaitForSingleObject(myEvent, INFINITE);
    }
 
    void SetCondition()
    {
        SetEvent(myEvent);
    }
 
    static DWORD WINAPI MyThreadFunction( const 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( const 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.resize(100);
        multithreadfunction=SetFunction;
    }
 
    Multithread( function<void(LPVOID)> SetFunction )
    {
        mtparameterthread.resize(100);
        multithreadparameterfunction =SetFunction;
    }
 
    //corrigir
    template<typename tpVariant>
    Multithread( function<void(tpVariant)> SetFunction )
    {
        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=lpParam;
        DebugText(to_string(vrParam));
 
        hThread= CreateThread(
            NULL,                   // default security attributes
            0,                      // use default stack size
            Multithread::MyParameterThreadFunction,       // thread function name
            static_cast<LPVOID>(&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;
        LPVOID lptest=static_cast<LPVOID>(&mtparameterthread[i]);
        hThread= CreateThread(
            NULL,                   // default security attributes
            0,                      // use default stack size
            &Multithread::MyParameterThreadFunction,       // thread function name
            lptest,          // 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);
    }
};

how use it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//these sample is on a class, that's why the 2nd brakes
Multithread mtRead{ [&]( LPVOID varname)
    {
 
        string *strTest=static_cast<string*>(varname);
        blnread=true;
        /*
        ostringstream  address;
        address << strTest;
        std:string name = address.str();
        DebugText(name);*/
        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));
        }
 
        *strTest=readstring;
        readstring="";
    }};
 
//call it:
mtRead(&txttext);

now heres cames the question:

1 - why works now and the variables adress's are saved?
- i'm using a vector for save the variable adress. now i can a new data without lose the last one. maybe isn't the best resize the vector to 100(because if i only need call it 10 time, the vector is consuming more memory that needs it), but, for now, it's working greate.

2 - why i don't lose the new thread order?
- simple after create a new thread i delay 100 milliseconds. of course using the CreationOrder(), we can change that

i hope these class helps others, like is help me
thanks to all
Delaying the thread for a specific time doesn't guarantee to make your threads execute in a specific order. It becomes a bit more likely (one thread gets a head start), but the task scheduler of the operating system can decide to make your created thread wait for a long time when performing a system call so it can execute other threads instead. It's all up to pure luck.

A better synchronization method would be to use a mutex, these are guaranteed to make one thread wait.

I wouldn't be using threads if you want all your code to execute in one specific order though, this would break the entire purpose of a thread.
Topic archived. No new replies allowed.