2

I am using the Skype API, which sends back a message everytime it receives one. I am not sure if this really is what is causing it, but it's the closest I can get: When I send too many messages, the COM control can't handle all the replies, which causes it to crash the whole app. That happens when I use a for loop.

I am using Threads to do the job, so my program won't hang. I know I can do Sleep(); in the thread, and will (should) not make the whole program sleep. The problem is though, that my COM control will be sleeping aswell, so it still wont be able to process whatever it needs, so it can keep up again.

So, the question is: How can I pause the routine without pausing the whole thread, so that the replies can be processed by my COM object, without overloading?

Jeff
  • 12,085
  • 12
  • 82
  • 152
  • 4
    As a general rule, anytime you think "I need to pause here for a few seconds," then that, to me, is a big fat code smell. – Nick Hodges Mar 22 '11 at 19:53
  • 1
    Sounds like a "state machine" is needed, to remember what is happening, what must happen next, how far through things it is, and the like. Send a message, wait to get the acknowledgement, then continue. – mj2008 Mar 23 '11 at 09:35
  • @Nick: I tend to agree with you. However, if you write data for something else faster than it's able to read and process it - you absolutely have to wait/slow down. The distinction comes: do you wait on time (bad idea)? or do you wait on an event (the best approach)? – Disillusioned Mar 26 '11 at 17:44
  • @Jeff: So off the back of my previous comment.... I suggest you dig around in the Skype API (unfortunately I'm not familiar with it), and look for something that can tell you when it's ready to receive more data or that can be leveraged to similar effect. Depending on exactly what it provides, it should be possible to get your thread to "wait until Skype is ready". – Disillusioned Mar 26 '11 at 17:48
  • @Craig: Skype should return a reply to the OnReply event handler, will look into that! – Jeff Mar 26 '11 at 18:00

4 Answers4

4

CoWaitForMultipleHandles can be used to block the thread, but still pump COM messages (in case of STA), some other Windows messages and has a timeout. Sounds like something you could use.

Lars Truijens
  • 42,837
  • 6
  • 126
  • 143
  • I looked it up, but I can't figure out how to use it in Delphi. Could you give me an example? :) – Jeff Mar 23 '11 at 15:17
  • Alright, it's in SyncObjs, however when I try to call it, I get "Undefined identifier: CoWaitForMultipleHandles", even though I do have SyncObjs in my Uses clause – Jeff Mar 23 '11 at 18:04
1

I tend to use TSimpleEvent for such cases. It may block your thread for a set amount of time (the time-out), but you may also wake up your thread with it externally (e.g. right before your call Terminate). It doesn't cost CPU. It may be deblocked by calls from other threads. I use this for threads that have to behave as if they are timed, e.g. wake up every 5 seconds and do something.

*) I Don't grasp your exact problem, but pausing in threads without sleeps is what I answered to. Maybe it can be used as (part of) your solution. Good luck with it.

MvdH
  • 145
  • 5
0

Sounds like the thread needs to test whether it should send a message each time it is called, rather than always sending one.

How to do this depends on the implementation; you may have some kind of condition that needs to be met (a size threshold, so you never send a message that is trivially small), or perhaps through rate limiting (check whether the last message sent long enough ago that you can afford to send another).

I hope this is helpful; I know it is very high-level.

Jonathan
  • 13,354
  • 4
  • 36
  • 32
  • No, I just need it to pause for a few secs, before continuing with the loop, so the COM control can keep up. – Jeff Mar 22 '11 at 19:07
  • So you want to pause one function of a thread while still allowing that thread to execute another function? Sounds like you need to split the one thread into two and use `Sleep()`. – Jonathan Mar 22 '11 at 19:08
  • I wish I could, but no, because the thread owns the Skype Object. – Jeff Mar 22 '11 at 19:13
  • Unless Delphi uses a significantly different threading model from other languages (not likely), it is not possible to interleave two functions within the same thread. Rate limiting and splitting into separate threads are your only options. Sorry I couldn't help more. – Jonathan Mar 22 '11 at 19:15
  • "it is not possible to interleave two functions within the same thread"... one word ... "fibers". :) Never used them myself so further research is left as an exercise for the reader, but they do exist (and they are an OS level facility, so yes, just as available to Delphi as to any other multithread capable language). – Deltics Mar 22 '11 at 21:24
  • @Deltics Fibers aren't a practical solution to any problem. Even MS had the devil's own job trying to get them to work properly in SQL Server and I think gave up in the end. – David Heffernan Mar 22 '11 at 22:25
  • I didn't say they were - I merely pointed out that they are a way to interleave N functions within a thread. This is the "COMMENTS" section, right? I was commenting. – Deltics Mar 23 '11 at 03:57
0

Could you use two threads, one for sending, one for receiving, and lock them like in this consumer/producer example ("Thread Synchronization with Guarded Blocks in Delphi", for Delphi 2009 and higher), so that a new message can only be sent by the producer when the consumer has processed it?

mjn
  • 36,362
  • 28
  • 176
  • 378