Pages

Thursday, July 17, 2008

OmniThreadLibrary progress report

WiPJust a short notice on what we're working on. I'm too tired to write a coherent article, longer than 100 words.

  • Lock-free structures are now really, really, really working.
  • Stress tests in tests\10_Containers have been significantly enhanced.
  • New Counter support.

The last item is really interesting and deserves a longer post. In short, it allows you to do:

counter := CreateCounter(2);

CreateTask(worker).WithCounter(counter).Run;

CreateTask(worker).WithCounter(counter).Run;

In worker code:

if Task.Counter.Decrement = 0 then

  Task.Comm.Send(MSG_ALL_DONE);

Decrement is interlocked, of course.

 

All that available in the repository and as a snapshot.

12 comments:

  1. Anonymous06:27

    Hi, very nice stuff!
    I have a question: How to organize our tasks into a thread group? They must run squential in a thread queue.

    1. TaskGroupA-Thread, jobs / tasks:
    - Task1
    - Task2
    - ...

    2. TaskGroupB-Thread, jobs / tasks:
    - Task1
    - Task2
    - ...

    Thanks!

    ReplyDelete
  2. Hmmm, interesting question. I think that there is no really simple way to do it.

    Possible solutions:

    1) Base each task on TOmniWorker class. Pass the next task to be run to the constructor of the previous class. In the Cleanup method of the task, run the next task.

    2) Implement the scheduling logic in the main program. Use OmniTaskEventDispatcher component to trap task terminations and run new tasks here.

    3) Implement each group as a separate thread pool. Set each thread pool max execution count to 1, and queue timeouts to an appropriate large number so that tasks won't be cancelled due to a timeout. Schedule all tasks for one group to the thread pool and it will take care of sequentially executing them.

    I don't have a good idea how to write a simple, reusable and flexible interface for task groups that would include sequential execution. Have you seen such syntax somewhere in practice or do you maybe have any ideas on how to do it?

    ReplyDelete
  3. Anonymous11:46

    I study your OTL library just a few minutes (a hour at least), not yet got enough knowledge regarding to the OTL architecture.

    But in practice, without changing your existing OTL structure, the three points you have thought is the right choice. But it's not elegant way. Making it built-in support about task grouping is more nice feature.

    Just my short opinian:
    1. Thread group could run using pool or not (depend on user requirement)

    2. I have see, most of new task creation push-ed using CreateTask function that return IOmniTaskControl; considering using this IOmniTaskControl as a group id & group controler; just as follow:

    Actualy in this requirement, we need create a function to register a group (may return cardinal of group ID etc), or user freely give us a unique id for each group that users need to use later.

    So when we need push a task using CreateTask, we could put the group id returned by group registration function (or user gived group id) as optional.
    Library should take care about this group parameter. If not 0 then find existing thread with group-id equal with parameter, if not exists create it (just create a thread as usualy and set the group-id --> we need add this property).

    After tasks in queue in a thread's tagged group completed (pool model), simply reset this thread-group-id to zero. So it can reuse freely by other new tasks that require no grouping / grouping. In non pool model just destroy this thread.

    For a moment maybe this what i could though, we can continue discuss if something missed :)

    Sorry my English...

    ReplyDelete
  4. Anonymous11:56

    If im not going wrong, is the ThreadPool has been completed & tested?

    ReplyDelete
  5. To answer the second comment first - ThreadPool is being worked on. I think you can expect the first release in few days.

    ReplyDelete
  6. An to answer the first comment: You points are perfectly valid. I did some work on a task groups yesterday and I think you have good ideas that deserve to be implemented.

    I also believe that they won't be implemented in version 1.0, but in the first following release (1.1, most probably).

    ReplyDelete
  7. What do you think of that proposal?

    1. Ability to chain tasks sequentially. IOmniTaskControl gets method

    function ChainTo(task: IOmniTaskControl; ignoreErrors: boolean = false): IOmniTaskControl;

    When task is completed and there were no errors (or ignoreErrors is set to True), chained task would start execution in the same thread. If outside code calls Terminate on the original task, whole chain would be terminated.

    2. Task groups. Current minimal interface (with even more simplicistic implementation):

    IOmniTaskGroup = interface ['{B36C08B4-0F71-422C-8613-63C4D04676B7}']
    // maybe: Comm: IOmniCommunicationEndpoint, which is actually one-to-many-to-one
    // function RunAll: IOmniTaskGroup;
    // fuction WaitForAll(maxWait_ms: cardinal = INFINITE): boolean;
    // function Sequential: IOmniTaskGroup;
    // function Parallel(useThreadPool: IOmniThreadPool): IOmniTaskGroup;
    function Add(taskControl: IOmniTaskControl): IOmniTaskGroup;
    function Remove(taskControl: IOmniTaskControl): IOmniTaskGroup;
    function TerminateAll(maxWait_ms: cardinal = INFINITE): boolean;
    end; { IOmniTaskGroup }

    You could run task group in sequential mode, fully parallel or on a thread pool.

    3. Ability to wrap a group inside a task.

    function CreateTask(worker: IOmniTaskGroup; const taskName: string = ''): IOmniTaskControl; overload;

    I think that covers all possible sequential-to-parallel-back-to-sequential scenarios.

    What do you (all my readers) think?

    ReplyDelete
  8. Anonymous12:11

    Exactly got the points!
    But, are you being overing us that 3 ways to be implemented or considering using one of them?

    I absolutely agree with the 2nd & 3rd points.
    What do you think?

    ReplyDelete
  9. I would implement all three.

    I know that the first approach is a duplicate - it can be implemented with a sequentially executed task group - but I have no problems with overloaded implementations. In simple cases, when (for example) you'd only want to run two tasks in sequence, using ChainTo would be much simpler than setting up a task group.

    ReplyDelete
  10. ChainTo is implemented. Commited to the repository together with the test program.

    Snapshot with the new functionality is not yet available.

    ReplyDelete
  11. Anonymous08:01

    Great news! I'll check this out ASAP.

    Both of those three methods is now implemented? Wow that fast :)

    ReplyDelete
  12. Not all three, just .ChainTo.

    ReplyDelete