Skip navigation.
Home
The QNX Community Portal

View topic - Mutex with DrawFunction for PtRaw

Mutex with DrawFunction for PtRaw

Isn't the name clear?

Mutex with DrawFunction for PtRaw

Postby m2asseli » Fri Apr 20, 2007 2:58 am

Hello,

I have a PtRaw widget which I am plotting points inside. The redraw function for the PtRaw (when it gets damaged) accesses a global structure. This structure gets updated in another thread, and thus, I had to use a mutex to ensure the redraw function did not access any of it's members while they were being modified.

The problem is, the mutex won't work!!! Are there any tricks to mutexes in Photon processes? I declared the mutex in a global header, initialized it to the default values (removed priority inheritance however), and lock it (or so I thought) before doing modifications to the variables. However, when I get into the redraw function, and I try to obtain the mutex, it doesn't block even though I just locked-it!

Any suggestions?
Thanks.
m2asseli
Senior Member
 
Posts: 100
Joined: Tue May 11, 2004 7:26 pm

RE: Mutex with DrawFunction for PtRaw

Postby maschoen » Fri Apr 20, 2007 5:27 am

Show us some code. Maybe build a very simple two threaded example that shows the problem?
maschoen
QNX Master
 
Posts: 2644
Joined: Wed Jun 25, 2003 5:18 pm

RE: Mutex with DrawFunction for PtRaw

Postby xtang » Fri Apr 20, 2007 8:23 pm

What function you use to "lock" the mutex, and what is the return value of that function?
xtang
QNX Master
 
Posts: 313
Joined: Thu Jul 18, 2002 5:01 pm

Postby m2asseli » Mon Apr 23, 2007 1:56 am

Here is a same code that gives the same "error" as my real code. The error code (45) shown in the output indicates that my thread already has the mutex locked, which is why it cannot lock it again. How can I get around this? The draw() function is called automatically when I attempt to create a new widget on the PtRaw widget.

Thanks.


----------------------------------------------------

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <Pt.h>

void draw(PtWidget_t * widget, PhTile_t * damage);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
PtArg_t args[4];
PhDim_t Dim = {100,100};
PhPoint_t Pos={10,10},Pos2={0,0};
PtWidget_t *Window,*Raw;

int main(int argc, char *argv[])
{
if( PtInit(NULL)==-1 )
exit(EXIT_FAILURE);
PtSetArg(&args[0], Pt_ARG_POS, &Pos, 0);
PtSetArg(&args[1], Pt_ARG_DIM, &Dim, 0);
if( (Window=PtCreateWidget(PtWindow,Pt_NO_PARENT,2,args)) == NULL)
PtExit(EXIT_FAILURE);

EOK,EAGAIN,EDEADLK,EFAULT,EINVAL,ETIMEDOUT);fflush(stdout);

PtSetArg(&args[0], Pt_ARG_POS, &Pos2, 0);
PtSetArg(&args[2], Pt_ARG_RAW_DRAW_F, &draw, 1 );
if( (Raw=PtCreateWidget(PtRaw,Pt_DEFAULT_PARENT,3,args)) == NULL )
PtExit(EXIT_FAILURE);
PtRealizeWidget(Window);

printf("Lock1: %i\n",pthread_mutex_lock(&mutex));fflush(stdout);
PtRealizeWidget(PtCreateWidget(PtButton,Pt_DEFAULT_PARENT,0,NULL));
printf("UnLock1: %i\n",pthread_mutex_unlock(&mutex));fflush(stdout);

PtMainLoop();
pthread_mutex_destroy( &mutex );
return EXIT_SUCCESS;
}
void draw( PtWidget_t *widget, PhTile_t *damage )
{
PtSuperClassDraw( PtBasic, widget, damage );
printf("Lock2: %i\n",pthread_mutex_lock(&mutex));fflush(stdout);
printf("Do some Raw Drawing.\n");fflush(stdout);
printf("UnLock2: %i\n",pthread_mutex_unlock(&mutex));fflush(stdout);

return;
}


----------------------------------------------------
OUTPUT:

Lock2: 0
Do some Raw Drawing.
UnLock2: 0
Lock1: 0
Lock2: 45
Do some Raw Drawing.
UnLock2: 0
UnLock1: 1
Lock2: 0
Do some Raw Drawing.
UnLock2: 0
m2asseli
Senior Member
 
Posts: 100
Joined: Tue May 11, 2004 7:26 pm

Postby maschoen » Mon Apr 23, 2007 5:09 am

m2asseli wrote:Here is a same code that gives the same "error" as my real code. The error code (45) shown in the output indicates that my thread already has the mutex locked, which is why it cannot lock it again. How can I get around this? The draw() function is called automatically when I attempt to create a new widget on the PtRaw widget.



The answer is very simple. Let me give you two very big hints.
45 = EDEADLK (Deadlock avoided).
This occurs when a thread which has locked a mutex tries to lock it again, non-recursively. Since it would have to wait for itself to unlock the thread, an event that can never happen while it is waiting, the OS returns an error indicating that the dead lock was avoided.

Note, this is not the same as one thread locking a mutex, and a second trying to lock it. In that case, thread 2 would become blocked waiting for thread 1.

I said 2 hints, but the 2nd should be very clear now, you are only dealing with ONE thread here.

Now take a look at your code, the output, and think about the relationship between the Realize call and the draw call, and you will learn something important.

Good luck.
maschoen
QNX Master
 
Posts: 2644
Joined: Wed Jun 25, 2003 5:18 pm

Postby m2asseli » Mon Apr 23, 2007 2:01 pm

I feel like I'm back in school.....with an electronic blackboard.

I realize that the PtRealize function invokes the PtRaw's draw function, since I am damaging the PtRaw's canvas by realizing a new widget (within the same thread). In my real code, I am changing values to a structure, which in turn creates new widgets over-top the PtRaw. By creating the new widgets, I am damaging the PtRaw and it's draw function gets called.....which in turn uses the structure which is being modified! Hence why I was trying to use a mutex to avoid accessing possibly invalid structure member values. Does this make sense to you?

Solution? Temporarily disable the draw function until I have completed the changes to the structure members, and have finished with the PtRealize functions. Afterwards, re-instate the draw function and damage the PtRaw, which will then be able to use VALID data from the structure's members.

Correct?
m2asseli
Senior Member
 
Posts: 100
Joined: Tue May 11, 2004 7:26 pm

Postby maschoen » Mon Apr 23, 2007 7:45 pm

Sorry about invoking teacher mode, I thought you might like to discover this yourself.
It's definitely a Doh! moment.
The reason are seeing this behavior is that PtRealize calls the Draw function.
Here is a psuedo version of what is happening.

main()
{

pthread_mutex_lock()
PtRealize();


}

PtRealize()
{

draw();

}

draw()
{

//This lock fails with 45
pthread_mutex_lock();

}

You only have one thread, so using a mutex is pointless here.
Maybe you are thinking of Java where the Java machine would
silently schedule a draw thread that you don't want to interfere with.

Maybe what is confusing is that with Photon there are other threads going on.
For example, the Photon kernel has a thread, and the video driver itself
has a thread. But these are in different processes, communicated to by
message passing. You don't have to worry about interfering with these.

The only reason you would need a mutex at all if you have more than
one thread in your own code, which you do not appear to.
If you did, you might keep the lock in the draw function, but
not call it in the main().
maschoen
QNX Master
 
Posts: 2644
Joined: Wed Jun 25, 2003 5:18 pm

Postby m2asseli » Mon Apr 23, 2007 9:27 pm

Yeah, the DOH hit pretty quick after your first posting.

For some reason I was under the impression that the draw function was called by PtRealize in a new thread, so it would block until I finished modifying my variables. I can see I will have to make some slight modifications to my code, but nothing too difficult.

Thanks maschoen.
m2asseli
Senior Member
 
Posts: 100
Joined: Tue May 11, 2004 7:26 pm

Postby tfletche » Thu Apr 26, 2007 12:42 am

Alternately, if you really are using multiple threads and this scenario is just an initialization "unfortunate situation" consider using a recursive mutex.
tfletche
QNX Master
 
Posts: 53
Joined: Wed Apr 11, 2007 11:19 am
Location: Ottawa


Return to GUI Programming

Who is online

Users browsing this forum: No registered users and 2 guests