-
December 17th, 2015, 04:01 PM
#1
[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
-
December 17th, 2015, 06:41 PM
#2
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.
-
December 19th, 2015, 07:25 AM
#3
Re: how make a multithread synchronization correctly?
Originally Posted by Arjay
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
-
December 19th, 2015, 07:53 AM
#4
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.
-
December 19th, 2015, 08:06 AM
#5
Re: how make a multithread synchronization correctly?
Originally Posted by Arjay
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.
-
December 19th, 2015, 08:42 AM
#6
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
-
December 19th, 2015, 09:23 AM
#7
Re: how make a multithread synchronization correctly?
Originally Posted by Cambalinho
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.
-
December 19th, 2015, 02:16 PM
#8
Re: how make a multithread synchronization correctly?
Originally Posted by Arjay
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
-
December 19th, 2015, 04:41 PM
#9
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.
-
December 20th, 2015, 05:59 AM
#10
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)
-
January 30th, 2016, 04:43 AM
#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.
-
January 30th, 2016, 05:00 AM
#12
Re: how make a multithread synchronization correctly?
Originally Posted by bestellen
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?
-
January 30th, 2016, 07:23 AM
#13
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
-
January 30th, 2016, 03:04 PM
#14
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
-
January 30th, 2016, 04:03 PM
#15
Re: [RESOLVED] how make a multithread synchronization correctly?
Originally Posted by Codeplug
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
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|