PDA

View Full Version : Problem emitting signal from a static function



Valheru
22nd May 2007, 15:00
I am writing a piece of code that handles callback from a C-library I link against. This library uses a callback function to show progress in a decoding run. I am using a static member function in a thread to act as the callback function, and I want to emit a signal from it to inform the GUI thread of the decoding progress. However, I can't get it to compile and I can't seem to find anyone who solved a similar problem. The error I am getting is:


/home/valheru/svn/knewz/src/decoder.cc: In static member function ‘static int Decoder::BusyCallback(void*, uuprogress*)’:
/home/valheru/svn/knewz/src/decoder.cc:40: error: cannot call member function ‘void Decoder::progress(const int&)’ without object

Does anyone know a workaround for this, or is it simply impossible to emit signals from static member of a class?

high_flyer
22nd May 2007, 15:27
Oh boy,this issue come time and again.
Have a look here (http://www.qtcentre.org/forum/f-qt-programming-2/t-how-to-emit-signal-in-a-static-function--6295.html/?highlight=callback)

Valheru
22nd May 2007, 15:39
Heh, I just finished reading that trainwreck >_<

But the problem remains, unfortunately. I HAVE to use a callback, since I am linking against the uulib library, which is about the best cross-platform library there is for decoding Usenet part-files. So short of writing my own (which I won't) I have to use it's callback function. Now, perhaps I could do something with a QEvent, since the callback function does not necessarily have to be a static member function. However, it still cannot emit a signal in that case, since a signal has to be emitted from an object. Still, a QEvent and a QApplication::postEvent() may work, but I am not sure how to get it to work, since it would still need an object (the GUI object) to be passed to as the first parameter of postEvent().

high_flyer
22nd May 2007, 15:49
Heh, I just finished reading that trainwreck
Well, the general solutions how to tranfer objects through callback (and thus be able to emit a signal of passed object) is in this post (http://www.qtcentre.org/forum/p-how-to-emit-signal-in-a-static-function--post32765/postcount10.html)

Valheru
22nd May 2007, 16:02
Ugh, how he solved it isn't really applicable in my case. The callback is called every 100 milliseconds, and the overhead of creating an object, setting up the signals and connecting the to the GUI threads slots is an excessive amount of overhead I feel, for such a simple thing. I appear to be getting somewhere with the QApplication::postEvent() approach - it's compiling at least :p However, I need to find out how to process the event in the GUI thread, and at the moment if I set up the QEvent and postEvent() it then the decoder never gets around to decoding the files, which is weird since psotEvent() just fires the
QEvent off and returns immediately according to the documentation :confused:

jpn
22nd May 2007, 16:09
Does the receiver reimplement QObject::customEvent() to catch the custom event? Is the event type larger or equal to QEvent::User?

high_flyer
22nd May 2007, 16:10
how he solved it isn't really applicable in my case

and


and the overhead of creating an object, setting up the signals and connecting the to the GUI threads slots is an excessive amount of overhead I feel

Have nothing in common.
Here is the code:


static void emitMsg( unsigned long user_value,char * filename)
{
myclass* pthis = (myclass*)user_value; // get this address
pthis->emit storescpProgressInfo(filename) ;
}

No allocation, no setting up connections, no nothing, just emiting a signal.
You set the connection there where the emitting and receiving object are visible, and you only need to do it once.
But then again, I don't really know what it is you are trying to do (appart from emiting a signal in a callback.).

Valheru
22nd May 2007, 16:24
Does the receiver reimplement QObject::customEvent() (http://doc.trolltech.com/latest/qobject.html#customEvent) to catch the custom event? Is the event type larger or equal to QEvent::User?

No, I hadn't set it up yet but I was busy doing so. I thought I would just fire off the event and made sure I was on the right track. Didn't expect it to stop the decoder working...
I am using QEvent::User as the event type though.

Valheru
22nd May 2007, 16:26
and


Have nothing in common.
Here is the code:


static void emitMsg( unsigned long user_value,char * filename)
{
myclass* pthis = (myclass*)user_value; // get this address
pthis->emit storescpProgressInfo(filename) ;
} No allocation, no setting up connections, no nothing, just emiting a signal.
You set the connection there where the emitting and receiving object are visible, and you only need to do it once.
But then again, I don't really know what it is you are trying to do (appart from emiting a signal in a callback.).

You are right, the slots would only be set up when the decoder si initially created. However, it seems a bit messy. If the way I'm trying to do it now doesn't work I'll give it a shot.

high_flyer
22nd May 2007, 16:36
But what is the way you are trying?
I am not clear on how you want to integrate QEvent in the external library?
Is it an open source lib?

Valheru
22nd May 2007, 16:53
Was my explanation that bad?

I am decoding files in a QThread. I am doing that using an open-source library, called uulib. It is THE library for decoding Usenet multipart files, which is what my program does. Well, it downloads them, but you get the picture. Now, rather than go through all the hassle of reinventing the wheel, I link against uulib and let it decode the files for me that my program has downloaded. However, uulib is a C library, and uses function callbacks to do certain things, one of which is to display it's progress during decoding. I would like to set up a function callback, and then do some calculations in it to determine the progress so far, and then to fire off a signal to the GUI thread so that it can update a progress bar with the progress of the decoder. Hence my whole problem :)

Valheru
22nd May 2007, 16:59
No, I hadn't set it up yet but I was busy doing so. I thought I would just fire off the event and made sure I was on the right track. Didn't expect it to stop the decoder working...
I am using QEvent::User as the event type though.


Ok, that sucks. When the event is caught in the main GUI thread, I then access the other thread using a public function to get the current progress. however, this causes the program to crash immediately. Is it forbidden to access QThreads this way? In Java I can simply use a public function with no ill effects between threads - is that possible with QThreads? Or should I set up some round-robbin thread/slot implementation?

marcel
22nd May 2007, 17:09
Does that function do any other stuff?

Regards

jpn
22nd May 2007, 17:16
Why not bundle the progress into the QEvent object?

Valheru
22nd May 2007, 18:33
Why not bundle the progress into the QEvent object?

I don't know how :( The docs don't mention it either as far as I can see, unless you mean by subclassing it?

marcel
22nd May 2007, 18:39
Yes, of course you have to create a custom event.
Don't forget to give it an id greater or equal that QEvent::User.

You can add some extra members to your subclass to hold the progress data and whatever you may need.

jpn
22nd May 2007, 19:39
See the attached example.

Michiel
22nd May 2007, 20:20
I'm not sure if a solution has been found yet, but maybe you could simply keep a single global object to which to connect signals/slots. This could be a global variable or a singleton object or something similar. You can control that object from your static function.

wysota
22nd May 2007, 20:29
I think that was already suggested in the other thread. From what I've read here, the solution with posting a custom event I find most appealing as you don't need a "sender" object for that.

Using a global object should work but at the same time violates some rules of good design, while the solution using events directly seems to be ok.

high_flyer
22nd May 2007, 20:56
Was my explanation that bad?
Probably not, but since I am doing it "along side" my work, my concentration can span so much :rolleyes:

In Java I can simply use a public function with no ill effects between threads - is that possible with QThreads? Or should I set up some round-robbin thread/slot implementation?

Well, in C++ you have to make sure the function is thread safe - that means - that there is no situation where two threads are trying to access the same reasorce at the same time.
You should use mutex or semaphores to protect the mutual excluded code.

I too vote for the custom event solution, its the "cleanest".

wysota
22nd May 2007, 21:59
In Java you have to do the synchronisation as well of course... It's not as simple as calling any function doing anything you want anywhere you want.

Valheru
12th June 2007, 14:48
Sorry I didn't update this thread sooner. I did indeed solve it by subclassing QCustomEvent. In the end the solution was simple to implement, and works very well. Thank you all for your help and patience.

/edit : the crash was being caused by accessing a function running in another thread directly. It was solved by bundling the data in the subclassed QCustomEvent as suggested.