2

I just discovered OmniThreadLibrary & started playing with it. I'm trying to launch, say, no more than 20 tasks max and send the rest of the tasks to queue.

I modified the OmniThreadLibrary's 00_Beep project to do this:

const
  TASKS_COUNT = 100;

procedure TfrmTestSimple.btnBeepClick(Sender: TObject);
var
    I: Integer;
begin
    with OmniEventMonitor do
        for I := 1 to TASKS_COUNT do
            Monitor(CreateTask(Beep, 'Beep-' + IntToStr(I))).Schedule;
end;

procedure TfrmTestSimple.FormCreate(Sender: TObject);
begin
    GlobalOmniThreadPool.MonitorWith(OmniEventMonitor);
    GlobalOmniThreadPool.MaxExecuting := 20;
    GlobalOmniThreadPool.MaxQueued := 0;
end;

It works but if I increase the # of tasks (ie. TASKS_COUNT) to, say, 7000, I get an exception:

TOmniCommunicationEndpoint.Send: Queue is full

I read whatever I could find (OTL blog and forums, sample projects, googled a lot, etc...), it seems that to prevent this, I must empty the queue periodically.

So I tried this but it didn't work:

procedure TfrmTestSimple.OmniEventMonitorTaskTerminated(const task: IOmniTaskControl);
begin
    Task.Terminate(1);       // I also tried: Task.Terminate(0);
    Task.Comm.Reader.Empty;  // Task.Comm.OtherEndpoint.Reader.Empty; didn't work either
    Task.Comm.Writer.Empty;  // Task.Comm.OtherEndpoint.Writer.Empty; didn't work either
end;

Any advice on how to empty the queue and avoid this exception?

I know that some may say that such a large number of tasks in queue is ridiculous, suffice to say it's neither a hypothetical question nor it's in the scope of my question to tell me to redesign my application, at this point I just need to know the limit of the queuing system in OTL and how to bypass this limitation.

Thanks in advance!

Maciej
  • 7,871
  • 1
  • 31
  • 36
TheDude
  • 3,045
  • 4
  • 46
  • 95
  • 1
    The abbreviation "AV" means *access violation*. Is that really what you're getting? It looks like you're just getting an ordinary logic error — the queue is full, and you're trying to put more stuff in it. To empty it, do you want to *block* your program until the queued items are executed, or do you want to *abandon* the queued items and resume queuing new items? – Rob Kennedy Jan 30 '12 at 20:46
  • OTL comes with source, does it not? Grep through the files, looking for the error text. Find out what raises the exception. Note how very hard I'm trying to not mention the 7000 queued items... – Martin James Jan 30 '12 at 20:49
  • 1
    @Rob: I tracked the sources, OTL is rising an exception. Ideally I'd like the queue to dynamically expand itself (I *just* started playing with OTL like 24h hours, I still don't understand OTL fully) – TheDude Jan 30 '12 at 21:30
  • As Rob said, that looks more like an exception than an access violation. The difference between them is important; the first is a logic error, the second is an unforeseen circumstance that should never have happened. The dialog should specifically say `raised E` for an exception, and `Access Violation` for an AV. – Ken White Jan 30 '12 at 21:33
  • @Martin: I did, and I reached a dead-end (do you really think I'd be here if I could something about it?) I'm trying very hard to not mention your harsh attitude (give me a break, I *just* started playing with OTL) – TheDude Jan 30 '12 at 21:35
  • @Ken: I edited my comment, as I said I meant an exception not an AV. (thank you, I *do* understand the difference) – TheDude Jan 30 '12 at 21:39
  • You edited four minutes after I posted my comment, which means it was valid at the time it was made. Since you originally wrote `AV`, it wasn't clear that you **do** understand the difference. You seem to want to take things said as personal insults rather than constructive advice or criticism; you shouldn't do that. :) – Ken White Jan 30 '12 at 21:42
  • @Ken: my apologies, I'm not insulted by constructive criticism, I'm actually frustrated by the issue itself. – TheDude Jan 30 '12 at 21:51
  • No offence intended :) A dynamic queue ss surely possible, but will take longer to manage inside the queue lock, so impacting contention. OTL probably went with performance over the flexibility to handle 7K objects plus. Another issue is that Windows message queues can only handle 10K items, so any inter-thread comms library that includes comms with the main thread via. PostMessage is going to be stuck with inconsistent performance if some queues can only handle 10K and others more, (that said, 7K is a strange limit..). – Martin James Jan 30 '12 at 21:53
  • 1
    Looking briefly at the code, I found a const 'CDefaultQueueSize = 1000;' in the OtlComm unit. Also an interesting call in 'OtlThreadPool: 'owtCommChannel := CreateTwoWayChannel(100, owtTerminateEvent);' I couldn't find anything set to 7000. You should look at these limits - one or more may be relevant. How many threads in your pool - I think that each pool thread may have a separate input queue, (size 100?). – Martin James Jan 30 '12 at 22:23
  • @Martin: thank you for the explanation, I was thinking the OTL queue would act like a TStringList (once a task is completed, OTL gets the next entry in queue/list, run it as a task and delete it from queue). Regarding comm/messages, as there can be no more than 20 tasks max, I thought it wouldn't be a problem since comm only affects active tasks, not completed or future ones. Clearly I was wrong. Thank you, that's what I needed to know :) – TheDude Jan 30 '12 at 22:25
  • Can you please answer my other question? Before the queue is empty, do you want all the queued items to be executed, so do you want to abandon them without running them? – Rob Kennedy Jan 30 '12 at 22:29
  • 2
    @Rob: My apologies, I should have been more explicit. I initially thought that whenever a task is completed, OTL reads the next task's info from the queue, start the new task, then deletes it from the queue. At least that's what I thought the OTL's queue is doing. So to answer your question: neither options are good for me, ideally I'd like the queue to dynamically expand/shrink (ie. once a task is started, it's removed from the queue and moved to the pool). But it seems that it's not possible...? – TheDude Jan 30 '12 at 22:45
  • 2
    Note that OTL queues are ring buffers, probably to avoid allocations/deallocations when pushing/popping. The size of the ring buffers is set during initialization. – LU RD Jan 30 '12 at 23:31
  • @Gdhami: I suggest you to get in touch with the [gabr](http://stackoverflow.com/users/4997/gabr) (the author is an SO member). – menjaraz Feb 24 '12 at 16:39
  • @menjaraz: Thank you, I found this (which basically answer my question): http://otl.17slon.com/forum/index.php/topic,354.0.html – TheDude Feb 24 '12 at 17:56
  • 1
    You are welcome. You can post it as an answer (elaborate a little if need be) and accept it. – menjaraz Feb 24 '12 at 18:31

1 Answers1

2

Well, this form post doesn't show how to empty OmniThreadLibrary ThreadPool queue, but it does show how to make a virtually unlimited waiting queue for OmniThreadLibrary (which is basically my goal):

http://otl.17slon.com/forum/index.php/topic,354.0.html

Thanks for all the help that I've received here, you guys are awesome!

TheDude
  • 3,045
  • 4
  • 46
  • 95
  • 3
    @vavan: The whole forum is down right now, but you can read the whole thread using the wayback machine: http://web.archive.org/web/20120426231342/http://otl.17slon.com/forum/index.php/topic,354.0.html – TheDude Jan 08 '14 at 15:09