Project Home
Project Home
Documents
Documents
Wiki
Wiki
Discussion Forums
Discussions
Project Information
Project Info
Forum Topic - Waiting on a thread: (10 Items)
   
Waiting on a thread  
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;
}
Re: Waiting on a thread  
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?
Re: Waiting on a thread  
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?


Re: Waiting on a thread  
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?
> 
> 


Re: Waiting on a thread  
> 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...
Re: Waiting on a thread  
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
Re: Waiting on a thread  
> 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.
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.


RE: Waiting on a thread  
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
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
> 
>