Kendall Russell
06/30/2011 11:39 AM
post86992
|
This might not really have anything to do with the microGUI, so if it is in the wrong forum, just let me know.
I am attempting to wait for a thread from a third party library to finish before my code continues to process.
The third party library (TCP library) basically starts a thread to send a message over a socket to another computer.
Basically, I provide the TCP library a callback function that it invokes when the response is received.
The callback function is always invoked after the wait period that I establish for the pthread_cond_timedwait(). No
matter how long I make the wait period, the callback function seems to be on hold until after that is over.
Any ideas?
Here is my code so far:
int PatComSendMessageW(char* pszMessage, const int len, const long nTimeOut)
{
int nWaitError = 0;
struct timespec timeWait = {0};
g_pComClient = TCPClientConstructor(Trp_IP,
Trp_Port,
FLAG_READ_TIMEOUT,
PatComRecvMessage); //PASSING CALLBACK
//LOCK MUTEX
pthread_mutex_lock(&g_ReadMutex);
//SEND MESSAGE
TCPWriteTimed(g_pComClient, pszMessage, len, nTimeOut);
//SET AMOUNT OF TIME TO WAIT
timeWait.tv_sec = time(0) + 15;
timeWait.tv_nsec = 0;
//WAIT FOR MESSAGE
nWaitError = pthread_cond_timedwait(&g_ReadEvent, &g_ReadMutex, &timeWait);
pthread_mutex_unlock (&g_ReadMutex);
return 0;
}
void PatComRecvMessage(struct Socket* pComClient,
int nComEvent,
char* pszMessage,
int nMsgLen,
int nComError)
{
int nError = 0;
PtEnter(NULL);
WdgtAppendText(ABW_LgnTxtWarnMsg, "PatComRecvMessage\n");
PtBkgdHandlerProcess();
PtLeave(NULL);
do
{
if(!pszMessage || nMsgLen < 1)
{
nError = -1;
WdgtSetText(ABW_LgnTxtErrorMsg,"TRP: Received Empty Reply");
break;
}
switch(nComEvent)
{
case TCP_EVENT_READ_DATA:
PtEnter(NULL);
WdgtSetText(ABW_LgnTxtErrorMsg,"TRP: Received Reply");
PtLeave(NULL);
break;
case TCP_EVENT_READ_ERROR:
PtEnter(NULL);
WdgtSetText(ABW_LgnTxtErrorMsg,"TRP: Read Error");
PtLeave(NULL);
break;
default:
PtEnter(NULL);
WdgtSetText(ABW_LgnTxtErrorMsg,"TRP: Unknown Event on Socket");
PtLeave(NULL);
break;
}
}while(0);
pthread_cond_signal(&g_ReadEvent);
return;
}
|
|
|
Wojtek Lerch
06/30/2011 2:08 PM
post86998
|
What calls PatComSendMessageW()? Is it by any chance some sort of a Photon callback that runs with the Photon library
locked? If that's the case, then PatComRecvMessage() in the other thread is getting stuck in its PtEnter() call.
Also, PatComRecvMessage() seems to signal the condvar without locking g_Read_Mutex. How do you make sure that the
pthread_cond_signal() doesn't happen before PatComSendMessageW() calls pthread_cond_timedwait()? Also, you don't seem
to be doing anything about spurious wakeups -- is that something you're planning to add later?
Have you considered using PtCondWait() or PtCondTimedWait() instead of pthread_cond_timedwait(), and the PtEnter() lock
instead of g_Read_Mutex?
|
|
|
Kendall Russell
06/30/2011 2:47 PM
post87000
|
The PatComSendMessageW() is called from a function that is a callback for a PtButton widget.
So, the user clicks the [Logon] button and the callback calls this function to send the logon credentials to the
database.
I don't have the PatComRecvMessage() set the mutex because I am not trying to protect any shared memory, I just want my
main thread to wait until a logon response is returned from the database. The callback signals that the condition is
complete when that happens.
I didn't know about PtCondWait or PtCondTimedWait. I will look at those.
Thanks for the information!
Kendall
> What calls PatComSendMessageW()? Is it by any chance some sort of a Photon
> callback that runs with the Photon library locked? If that's the case, then
> PatComRecvMessage() in the other thread is getting stuck in its PtEnter() call
> .
>
> Also, PatComRecvMessage() seems to signal the condvar without locking
> g_Read_Mutex. How do you make sure that the pthread_cond_signal() doesn't
> happen before PatComSendMessageW() calls pthread_cond_timedwait()? Also, you
> don't seem to be doing anything about spurious wakeups -- is that something
> you're planning to add later?
>
> Have you considered using PtCondWait() or PtCondTimedWait() instead of
> pthread_cond_timedwait(), and the PtEnter() lock instead of g_Read_Mutex?
|
|
|
Kendall Russell
06/30/2011 3:47 PM
post87003
|
The PtCondTimedWait() seems to be working correctly. I don't understand why since it appears to be doing the same thing
as the pthread_cond_timed() function.
When you mentioned checking for spurious wakeups before, can you elaborate a little?
Would I just need to check the return code to see why it returned to make sure it was why I was expecting it to return?
Thanks again,
Kendall
>
> The PatComSendMessageW() is called from a function that is a callback for a
> PtButton widget.
>
> So, the user clicks the [Logon] button and the callback calls this function to
> send the logon credentials to the database.
>
> I don't have the PatComRecvMessage() set the mutex because I am not trying to
> protect any shared memory, I just want my main thread to wait until a logon
> response is returned from the database. The callback signals that the
> condition is complete when that happens.
>
> I didn't know about PtCondWait or PtCondTimedWait. I will look at those.
>
> Thanks for the information!
>
> Kendall
>
> > What calls PatComSendMessageW()? Is it by any chance some sort of a Photon
>
> > callback that runs with the Photon library locked? If that's the case, then
>
> > PatComRecvMessage() in the other thread is getting stuck in its PtEnter()
> call
> > .
> >
> > Also, PatComRecvMessage() seems to signal the condvar without locking
> > g_Read_Mutex. How do you make sure that the pthread_cond_signal() doesn't
> > happen before PatComSendMessageW() calls pthread_cond_timedwait()? Also,
> you
> > don't seem to be doing anything about spurious wakeups -- is that something
>
> > you're planning to add later?
> >
> > Have you considered using PtCondWait() or PtCondTimedWait() instead of
> > pthread_cond_timedwait(), and the PtEnter() lock instead of g_Read_Mutex?
>
>
|
|
|
Wojtek Lerch
06/30/2011 5:44 PM
post87006
|
> The PtCondTimedWait() seems to be working correctly. I don't understand why
> since it appears to be doing the same thing as the pthread_cond_timed()
> function.
Not exactly: the pthread function unlocks a mutex when going to sleep. The Pt function unlocks the Photon library.
Unlocking the Photon library is what allows the PtEnter() in the other thread to come through.
> When you mentioned checking for spurious wakeups before, can you elaborate a
> little?
This is what POSIX says about it:
<QUOTE src="http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html">
When using condition variables there is always a Boolean predicate involving shared variables associated with each
condition wait that is true if the thread should proceed. Spurious wakeups from the pthread_cond_timedwait() or
pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not
imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.
</QUOTE>
In other words, pthread_cond_wait() may sometimes return zero even though nobody has signalled the condvar (yet).
That's why it's important to have a separate variable to confirm that the wakeup was intentional; and it also makes it
important to lock the mutex in the signalling thread, to protect your variable and to ensure that you don't signal the
condvar before the other thread calls wait.
(If nobody is waiting on a condvar when you signal it, the signal is a no-op. The signal doesn't get saved to
immediately wake up the next wait call. If you call cond_wait() after the signal(), you'll end up sleeping forever or
until you time out.)
> Would I just need to check the return code to see why it returned to make sure
> it was why I was expecting it to return?
No, because a return code of zero doesn't necessarily mean that signal was called.
> > The PatComSendMessageW() is called from a function that is a callback for a
> > PtButton widget.
Right, and therefore it is called with the Photon library locked. You'll need to call either PtLeave() and then
PtEnter(), or PtCondWait(), to temporarily unlock it and let the other thread's PtEnter() come through.
> > So, the user clicks the [Logon] button and the callback calls this function
> to
> > send the logon credentials to the database.
> >
> > I don't have the PatComRecvMessage() set the mutex because I am not trying
> to
> > protect any shared memory, I just want my main thread to wait until a logon
>
> > response is returned from the database. The callback signals that the
> > condition is complete when that happens.
> >
> > I didn't know about PtCondWait or PtCondTimedWait. I will look at those.
> >
> > Thanks for the information!
> >
> > Kendall
> >
> > > What calls PatComSendMessageW()? Is it by any chance some sort of a
> Photon
> >
> > > callback that runs with the Photon library locked? If that's the case,
> then
> >
> > > PatComRecvMessage() in the other thread is getting stuck in its PtEnter()
>
> > call
> > > .
> > >
> > > Also, PatComRecvMessage() seems to signal the condvar without locking
> > > g_Read_Mutex. How do you make sure that the pthread_cond_signal() doesn't
>
> > > happen before PatComSendMessageW() calls pthread_cond_timedwait()? Also,
>
> > you
> > > don't seem to be doing anything about spurious wakeups -- is that
> something
> >
> > > you're planning to add later?
> > >
> > > Have you considered using PtCondWait() or PtCondTimedWait() instead of
> > > pthread_cond_timedwait(), and the...
|
|
|
Kendall Russell
07/06/2011 2:37 PM
post87155
|
Wojtek Lerch: Thank you for your help. You have taught me a lot that I didn't know.
Can you (or anyone) point me to the documentation that explains what is done before the callbacks are invoked? Is
PtEnter called before any and every callback or just certain types?
Thanks,
Kendall
|
|
|
Wojtek Lerch
07/06/2011 5:00 PM
post87169
|
> Can you (or anyone) point me to the documentation that explains what is done
> before the callbacks are invoked? Is PtEnter called before any and every
> callback or just certain types?
Actually, the Photon library Calls PtLeave() before going to sleep waiting for an event, but then calls PtEnter as soon
as it wakes up and has something to process, such as a Photon event (possibly triggering various widget callbacks), an
external message or pulse (causing an "input proc" to be called), or even the absence of an event (if you have a "
workproc" registered). In a nutshell, pretty much whenever Photon library code is running, it runs with the PtEnter
thing locked. When it calls your code, you're generally allowed to unlock it temporarily, either by calling PtLeave()
and PtEnter() yourself or by calling something else that temporarily unlocks the library for you, such as PtCondWait()
or PtPrompt() or PtFileSelection(); but it's your responsibility to lock it back before you return.
|
|
|
Kendall Russell
07/07/2011 10:41 AM
post87191
|
Thank you for the explanation, but do you (or anyone) know if this is documented in official QNX documentation and, if
so, where?
I am asking because I am eventually going to have to turn over my code to another group in our company. I am going to
have to explain my usage of PtEnter and PtLeave as they are very concerned that we are not using it correctly and that
we could lock up the entire application. While their concern is valid, I don't think they understand that the system is
already calling PtEnter in a lot of cases.
My best course of action will be to give them or point them to the official documentation that explains this behavior.
Thank you
Kendall
> > Can you (or anyone) point me to the documentation that explains what is done
>
> > before the callbacks are invoked? Is PtEnter called before any and every
> > callback or just certain types?
>
> Actually, the Photon library Calls PtLeave() before going to sleep waiting for
> an event, but then calls PtEnter as soon as it wakes up and has something to
> process, such as a Photon event (possibly triggering various widget callbacks)
> , an external message or pulse (causing an "input proc" to be called), or even
> the absence of an event (if you have a "workproc" registered). In a nutshell
> , pretty much whenever Photon library code is running, it runs with the
> PtEnter thing locked. When it calls your code, you're generally allowed to
> unlock it temporarily, either by calling PtLeave() and PtEnter() yourself or
> by calling something else that temporarily unlocks the library for you, such
> as PtCondWait() or PtPrompt() or PtFileSelection(); but it's your
> responsibility to lock it back before you return.
|
|
|
Steve Reid
07/07/2011 10:46 AM
post87192
|
Here's a link to a section in the Parallel Operations chapter of the
Photon Programmer's Guide:
http://www.qnx.com/developers/docs/6.5.0/topic/com.qnx.doc.photon_prog_g
uide/lengthy.html#Threads
I hope it helps.
Steve Reid (stever@qnx.com)
Technical Editor
QNX Software Systems
> -----Original Message-----
> From: Kendall Russell [mailto:community-noreply@qnx.com]
> Sent: Thursday, July 07, 2011 10:41 AM
> To: photon-graphics
> Subject: Re: Waiting on a thread
>
> Thank you for the explanation, but do you (or anyone) know if this is
> documented in official QNX documentation and, if so, where?
>
> I am asking because I am eventually going to have to turn over my code
> to another group in our company. I am going to have to explain my
> usage of PtEnter and PtLeave as they are very concerned that we are
not
> using it correctly and that we could lock up the entire application.
> While their concern is valid, I don't think they understand that the
> system is already calling PtEnter in a lot of cases.
>
> My best course of action will be to give them or point them to the
> official documentation that explains this behavior.
>
> Thank you
> Kendall
>
> > > Can you (or anyone) point me to the documentation that explains
> what is done
> >
> > > before the callbacks are invoked? Is PtEnter called before any
and
> every
> > > callback or just certain types?
> >
> > Actually, the Photon library Calls PtLeave() before going to sleep
> waiting for
> > an event, but then calls PtEnter as soon as it wakes up and has
> something to
> > process, such as a Photon event (possibly triggering various widget
> callbacks)
> > , an external message or pulse (causing an "input proc" to be
> called), or even
> > the absence of an event (if you have a "workproc" registered). In
a
> nutshell
> > , pretty much whenever Photon library code is running, it runs with
> the
> > PtEnter thing locked. When it calls your code, you're generally
> allowed to
> > unlock it temporarily, either by calling PtLeave() and PtEnter()
> yourself or
> > by calling something else that temporarily unlocks the library for
> you, such
> > as PtCondWait() or PtPrompt() or PtFileSelection(); but it's your
> > responsibility to lock it back before you return.
>
>
>
>
>
>
> _______________________________________________
>
> Photon microGUI
> http://community.qnx.com/sf/go/post87191
|
|
|
Kendall Russell
|
Re: RE: Waiting on a thread
|
Kendall Russell
07/07/2011 12:18 PM
post87194
|
Re: RE: Waiting on a thread
Thanks, that seems to be exactly what I am looking for.
Kendall
> Here's a link to a section in the Parallel Operations chapter of the
> Photon Programmer's Guide:
>
>
> http://www.qnx.com/developers/docs/6.5.0/topic/com.qnx.doc.photon_prog_g
> uide/lengthy.html#Threads
>
> I hope it helps.
>
> Steve Reid (stever@qnx.com)
> Technical Editor
> QNX Software Systems
>
>
|
|
|
|