Page 1 of 1

On AsyncDo and ThreadSafeCall

Posted: Sat Nov 30, 2019 2:52 pm
by zarkogajic
Hi support,

I'm looking for a way to do something with a bunch of pdf documents in separate thread(s) ... browsing the sdk help, and I think I've found what seems to be the way to go - and would need some guidance / confirmation / explanations before I start heavy coding...

I have an array of PDFs and for each I'd need my custom IOperation to be executed *not* in the main app thread. I also need to be able to cancel the process at any point - something similar to how the op.search (inside a folder) works - the search results are populated in a different thread and the Stop button can be used to stop the search.

Here's how I think this should work and would like your comments :

Code: Select all

//pseudo

for each pdf do
{
1. IPXV_Inst::AsyncDo to run an IOperation (with pdf as input parameter) in background thread
2. During the execution of IOperation.Do periodically call IPXV_Inst::ThreadSafeCall 
3. In OnThreadSafeCall check main thread for "my stop flag" - if set exit the Do method (this will fire IPXV_AsyncDoCallback.OnFinishOp)
4. Check for stop flag in IPXV_AsyncDoCallback.OnStartOp to check if "this" operation in thread pool should even start executing.
}
Since there will be lots of pdfs the for lop will finish and the operations to be executed will be in some thread pool?

What will happen if the are operations still to be executed and I try to close the app (Inst.Shutdown)?

How may threads are used by sdk? Is this specified in Preferences - Performance - Threads / working threads ? If so, how do you determine the number of threads for "automatic" value?




-žarko

Re: On AsyncDo and ThreadSafeCall

Posted: Fri Dec 06, 2019 4:05 pm
by Sasha - Tracker Dev Team
Hello zarkogajic,

Forwarded this one for Vasyl for further investigation.

Cheers,
Alex

Re: On AsyncDo and ThreadSafeCall

Posted: Wed Dec 18, 2019 11:35 pm
by Vasyl-Tracker Dev Team
Hi -žarko.

Sorry for delay with answer.
for each pdf do
{
1. IPXV_Inst::AsyncDo to run an IOperation (with pdf as input parameter) in background thread
2. During the execution of IOperation.Do periodically call IPXV_Inst::ThreadSafeCall
3. In OnThreadSafeCall check main thread for "my stop flag" - if set exit the Do method (this will fire IPXV_AsyncDoCallback.OnFinishOp)
4. Check for stop flag in IPXV_AsyncDoCallback.OnStartOp to check if "this" operation in thread pool should even start executing.
}
That looks good, excepting the switching from the working thread to the main thread just for check cancel of work. There exists other simple and safe way to cancel all tasks. You may use our IFlag-object:

Code: Select all

// create one 'global' IFlag-object:
auxInst.CreateFlag(&myCancelFlag);

// create and start all tasks and share with them this one myCancelFlag
for (pdf : listOfPdfs)
{
       MyOperation op = new MyOperation(pdf, myCancelFlag);
       pdfInst.AsyncDo(op, ..);
}

// inside the operation
MyOperation::Do()
{
       // do some work with m_Pdf
       if (m_CancelFlag.Value)
       {
              return; // cancel the task
       }
       // do some work with m_Pdf
}

// then in the main thread, in UI, to stop all work

OnBtnCancel()
{
     myCancelFlag.Value = true;
     //
     // here, if you need, you may wait for all corresponding IPXV_AsyncDoCallback.OnFinishOp calls. 
     // Of course, while you wait, to keep the UI alive - you need also 'pump' all window's events..
}
- this method works without interlocking threads at all.
Since there will be lots of pdfs the for lop will finish and the operations to be executed will be in some thread pool?
Yes, the AsyncDo uses special internal thread pool.
What will happen if the are operations still to be executed and I try to close the app (Inst.Shutdown)?
For sure that is abnormal scenario. So before calling of Inst.Shutdown() I recommend you to wait for finish of each task, as I mentioned above. Especially when you working with documents in that tasks..
How may threads are used by sdk? Is this specified in Preferences - Performance - Threads / working threads ? If so, how do you determine the number of threads for "automatic" value?
Currently the thread-pool used by AsyncDo has a limits: you can run no more than 3 tasks at the time. So any other tasks will just wait for 'gap'.
Also the changing of the MaxNumOfWorkingThreads parameter in the Prefs/Performance - it may take effect on this. For example if you set 1 to it then the max-limit for the mentioned thread pool will be reduced to the 2 (because the minimum number of threads for that thread-pool is 2). To summarize all of it, the max-limit for that thread-pool calculates as:

Code: Select all

maxThreadsNum = Prefs.MaxNumOfWorkingThreads;
if (maxThreadsNum <= 0) // automatic
    maxThreadsNum = CpuCoresNum;
else
    maxThreadsNum = min(maxThreadsNum, CpuCoresNum);
maxThreadsForAsyncDo = min(maxThreadsNum, 3); // 3 - it can be increased in the future
maxThreadsForAsyncDo = max(maxThreadsForAsyncDo, 2);
Cheers.

Re: On AsyncDo and ThreadSafeCall

Posted: Thu Dec 19, 2019 9:45 am
by zarkogajic
Hi Vasly,

This is great, thanks! The IFlag is super handy.

Please do reconsider, in SDK, to allow increasing the max threads from 3 to whatever a developer specifies :)



Re: On AsyncDo and ThreadSafeCall

Posted: Thu Dec 19, 2019 10:16 am
by Sasha - Tracker Dev Team
Hello žarko,

Note, that using the operations in many threads can only be done on the IPXC level, meaning using the IPXV_Inst and IPXC_Document. If the operations are used in the multiple threads on the living IPXV_Control then there can be many troubles - undo/redo data (history), modification of one document from several threads etc. Thus you should limit the usage to the Core level where no control, events and history are present if you want to do multi thread work.

Cheers,
Alex

Re: On AsyncDo and ThreadSafeCall

Posted: Thu Dec 19, 2019 10:54 am
by zarkogajic
Hi Alex,

Yes, was aware of that :) Thanks.


Re: On AsyncDo and ThreadSafeCall

Posted: Thu Dec 19, 2019 12:11 pm
by Sasha - Tracker Dev Team
:)

Re: On AsyncDo and ThreadSafeCall

Posted: Mon Mar 30, 2020 9:51 am
by zarkogajic
Hi Support,

Just do double check: the methods of IPXV_AsyncDoCallback (OnStartOp / OnFinishOp) are *not* executed in the main thread, they are executed in the same thread where the Do() method of the IOperation takes place?


-žarko

Re: On AsyncDo and ThreadSafeCall

Posted: Mon Mar 30, 2020 3:35 pm
by zarkogajic
Hi support,

Did some tests: the answer is yes.


Re: On AsyncDo and ThreadSafeCall

Posted: Mon Mar 30, 2020 4:51 pm
by Sasha - Tracker Dev Team
:)

Re: On AsyncDo and ThreadSafeCall

Posted: Tue Mar 31, 2020 12:46 am
by Vasyl-Tracker Dev Team
Hi žarko.

In the new upcoming build you will be able to change in runtime the limit for background threads (started by AsyncDo) via:

Code: Select all

pdfCtl.Inst.Settings["Performance.MaxThreads"].v = 16;
pdfCtl.Inst.Settings["Performance.MaxBackgroundThreads"].v = 8;
pdfCtl.Inst.FireAppPrefsChanged(PDFXEdit.PXV_AppPrefsChanges.PXV_AppPrefsChange_Performance);
Cheers.

Re: On AsyncDo and ThreadSafeCall

Posted: Tue Mar 31, 2020 5:43 am
by zarkogajic
Hi Vasyl,

Fantastic!


Re: On AsyncDo and ThreadSafeCall

Posted: Tue Mar 31, 2020 8:05 am
by Sasha - Tracker Dev Team
:)

Re: On AsyncDo and ThreadSafeCall

Posted: Wed Apr 01, 2020 7:33 am
by zarkogajic
Hi support,

When adding IOperation "tasks" to the thread pool via Inst.AsyncDo - you are storing tasks in some queue like structure.

The order of task execution follows the order of adding to the queue.

So, if I do:

Inst.AsyncDo(IOp_1)
Inst.AsyncDo(IOp_2)
Inst.AsyncDo(IOp_3)
...
Inst.AsyncDo(IOp_N)

The execution will (kind of) be 1,2,3, .. N. We can say this is "normal" priority.

Is there a way for AsyncDo to specify the priority of the IOperation?

Say I'm adding the next task AsyncDo(IOp_M) - I'd like this one to be executed as soon as possible (when one of the threads used is finished executing "normal" priority tasks) - so like having "high" priority (kind of a new OpExecFlags value).

?

p.s.
I presume the answer is no, but experience tells me "you never know" :)

-žarko

Re: On AsyncDo and ThreadSafeCall

Posted: Wed Apr 01, 2020 1:19 pm
by Sasha - Tracker Dev Team
Hello zarkogajic,

From what I know, the AsyncDo uses a highest priority thread pool in the thread manager that is being registered when the instance is created. Basically what you give it will be done as soon as possible - so that's what you need in your case.

Cheers,
Alex

Re: On AsyncDo and ThreadSafeCall

Posted: Wed Apr 01, 2020 3:47 pm
by zarkogajic
Hi Alex,

Thanks, but that's not what I'm asking about.
what you give it will be done as soon as possible
That's ok, but the order of execution of IOperations will follow the order of them being sent to your internal thread pool.

I need some IOperations, added at a later time, to execute before some added before them (of course if they are not already executing).


-žarko

Re: On AsyncDo and ThreadSafeCall

Posted: Mon Apr 06, 2020 1:24 pm
by Sasha - Tracker Dev Team
Hello žarko,

I'm not sure that I understand your requirements correctly. You always can catch the Before Execture Operation event of some operation and then launch your own operation beforehand.

Cheers,
Alex

Re: On AsyncDo and ThreadSafeCall

Posted: Mon Apr 06, 2020 2:47 pm
by zarkogajic
Hi Alex,

I know what I ask for is probably not currently implemented :) But as we know "you never know".

Also, I'm not sure how to explain the idea/need in more details, so I'll try again:

When calling AsyncDo(some_IOperation) for multiple IOperations your internal code stores the "tasks" in a queue / thread pool.

Say I've sent 10 tasks to your internal queue via

Inst.AsyncDo(IOp_1)
Inst.AsyncDo(IOp_2)
...
Inst.AsyncDo(IOp_10)

At the moment your internal thread pool uses 3 threads (as stated by Vasyl in this topic)

For the sake of simplicity let's say that each task takes the same amount of time to be executed.

Meaning that "tasks" will be executed in the next order:

1. IOp_1 (thread 1)
2. IOp_2 (thread 2)
3. IOp_3 (thread 3)
4. IOp_4 (thread 1 or 2 or 3)
5. IOp_5 (thread 2 or 1 or 3)
6. IOp_6 (thread 3 or 1 or 2)
etc

Note how, for example, IOP_6 will be executed after all previous ([1,2,3]) have finished (or at least at the same time with the other tasks [4,5,6] in the group of 3).

What I need is to somehow say that IOP_9, for example, has the higher priority than other tasks (of course this makes sense only if IOP_9 is waiting to be executed).

This would mean that if we are at step (4) above, step 5 will not take task IOP_5 but the higher priority task IOP_9, then IOP_5 and the rest...

Hope this makes more sense.

-žarko

Re: On AsyncDo and ThreadSafeCall  SOLVED

Posted: Tue Apr 07, 2020 6:44 am
by Sasha - Tracker Dev Team
Hello zarkogajic,

Well you will have to manage such an advanced behavior for yourself. Basically your IOperation interface, that you pass to the AyncDo, will have to signal you that something is being completed so that you can continue with your logic onward. It can do that via the https://sdkhelp.pdf-xchange.com/vi ... DoCallback that you can pass to the AsyncDo method. The OnStartOp method will be called when the TaskManager starts doing some of it's tasks and the OnFinishOp is being called when the operation has finished it's work. You should store some needed data in your custom IOperation interface implementation to distinguish between the operations and act accrodingly.
That is what can be done.

Cheers,
Alex

Re: On AsyncDo and ThreadSafeCall

Posted: Tue Apr 07, 2020 6:48 am
by zarkogajic
Hi Alex,

Yes, thanks, that's what I'm doing at the moment. I though: maybe, just maybe, a "priority" value already exists when using AsyncDo.


Re: On AsyncDo and ThreadSafeCall

Posted: Tue Apr 07, 2020 6:49 am
by Sasha - Tracker Dev Team
:)