Threading...

Posted by Admin on 01-May-2009 04:08

Hi,

I wish to open a "progress bar" dialog box from a window while performing a potentially lengthy operation.

Am I right in thinking I will need to create a new "thread" for this?

I've discovered there is a BackgroundWorker component in .net but so far I have not been able to get it to

work successfully.

Could anyone shed some light on this for me?

Thanks.

All Replies

Posted by rbf on 01-May-2009 04:24

Hi Mark,

I have to disappoint you. Threading is not supported in the ABL.

The fact that the BackgroundWorker is available in the toolbox is a bug.

It does not work.

-peter

Posted by Admin on 01-May-2009 04:29

Ah, I see.

That's a shame.

Thanks for the help

Posted by Admin on 01-May-2009 06:06

We had a simlar discussion just recently: http://communities.progress.com/pcom/message/55584#55584

(And there's a link to another thread as well).

If the client is actualy busy - and not just waiting for a single long running DB operation or appserver call to finish - you can use an animated GIF in a PictureBox control. A PROCESS EVENTS or call to the :Refresh() method of the picturebox will update the image. Depending on the nature of the processing that's something you may do every n iterations of a loop or so.

Posted by Admin on 01-May-2009 06:14

The official term from the 10.2A EULA is that the use of threads is prohibited - and not just unsupported.

Posted by Admin on 01-May-2009 06:17

Once again, thanks to every body for your help!

Posted by Thomas Mercer-Hursh on 01-May-2009 11:37

You might want to also talk to your salesrep about how much you really want multithreading.

http://www.oehive.org/MultiThread

It's not trivial, but it is time to cross this bridge.

Posted by jquerijero on 16-Jun-2009 14:17

You can try hijacking the System.Timers.Timer which fires its Elapsed event in separate Thread. With what I know about .NET programming, application has a defualt ThreadPool even in a single threaded application. I'm not exactly sure if this was overlooked because it works somewhat. NOTE: You can not use a class level variable to to cancel the loop. ABL can not communicate variable changes on time to the Elapsed thread. The UI remains responsive while the loop is being processed just don't try to update any variables that are being used by the Elapsed event outside the event handler.

DEFINE PRIVATE VARIABLE timer AS System.Timers.Timer NO-UNDO.

timer = NEW System.Timers.Timer(100).

timer:Elapsed:SUBSCRIBE(timer_Elapsed).

timer:Enabled = TRUE.

METHOD PRIVATE VOID timer_Elapsed(INPUT source AS System.Object, INPUT e AS System.Timers.ElapsedEventArgs ):

DEFINE PRIVATE VARIABLE cntr AS INTEGER NO-UNDO.

DEFINE PRIVATE VARIABLE percent AS INTEGER NO-UNDO.

IF NOT isScanning THEN

DO:

isScanning = TRUE.

timer:Enabled = FALSE.

DO cntr = 0 TO 1000000:

percent = (cntr * 100)/ 1000000.

/* let's not spam the UI */

IF cntr MODULO 500 = 0 THEN

DO:

label1:Text = STRING(percent) + " : " + STRING(cntr).

END.

END.

isScanning = FALSE.

END.

END METHOD.

Normally the line with label1:Text is a cross-threading update violation.

Posted by Admin on 17-Jun-2009 02:00

I guess doing some "long running processing" withing the Timer's Elapsed event handler does not solve the orignal posters question:

I wish to open a "progress bar" dialog box from a window while performing a potentially lengthy operation.

So the progress bar should probably be updated from the Timers event, not the processing be done from the timers event.
I've attached a small solution (Consultingwerk.Demo.TimerDemoForm) that demonstrates the different behavior between System.Windows.Forms.Timer and System.Timers.Timer.
The fields ultraTextEditor1 and 2 are updated every 100 msec from the System.Timers.Timer and ultraTextEditor3 and 4 from the System.Windows.Forms.Timer.
The ultraButton1_Click event handler performs 15 seconds processing (incrementing the variable iProgress by 1).
You'll see that while within that loop, the System.Windows.Forms.Timer will fire whenever the PROCESS EVENTS statement is executed (and the timer interval has been reached). The System.Timers.Timer will not fire at all. So (in the AVM) I personally would rather go with the System.Windows.Forms.Timer and use PROCESS EVENTS every once in a while.
[View:~/cfs-file.ashx/__key/communityserver-discussions-components-files/19/TimerSample.zip:550:0]

Posted by jquerijero on 17-Jun-2009 08:43

You can at least use the Form's Timer to spin the progress bar in some interval, and use ONE elapsed event of the System Timer to do the long running process without losing UI responsiveness.

Posted by Admin on 17-Jun-2009 09:11

Did you try that out? If so, please post a running piece of code.

I just tried it and while in the Elapsed event of the System.Timers.Timer (doing the long processing) the whole UI is frozen, causing that I can't move the Form and the Elapsed evnet of the SWF Timer does not fire.

Posted by jquerijero on 17-Jun-2009 09:34

Hmmm, System and Form Timers don't want to play nicely. Just having the System timer won't lose the UI responsiveness, but having the Form Timer also anabled at the same time locks the UI.

Yes, the progress bar update needs to be inside the Elapsed time. Also, my comment is not about using System.Timers.Timer for processing in an interval, it's about using the timer pulse as pseudo-thread because it is a separate thread by the timer's implementation. Whatever/whereever that thread is running I don't know if the ABL is really enforcing a single-thread affinity.

Posted by Admin on 17-Jun-2009 09:59

It's not the two different timers that don't play nicely together. It's the AVM (Progress Virtual Machine) and multithreading that don't play together at all.

It's correct, that you can use (it's a different question if that's already violating the license agreement for OE10.2A, see below) the System.Timers.Timer and that might be living in it's own thread. But as soon as an ABL event handler (that's where your long running processing is happening) is executed this happens in the single threaded AVM. Good old unmanaged C code. ABL code is not executed in the CLR. The AVM hosts the CLR.

It's true that the UI seems to be responding (you can move around the window and you don't have repaint issues) - because that happens in the CLR.

But as soon as an event (let's say an button click or the event of the SWF timer) somewhere else executes and ABL event handler, this has to wait until the AVM is idle again, so when the long running event handler for the System.Timers.Timer:Elapsed event is finished.

So the user can move around the window, minimize and maximize it (as long a he has no ABL window-resized handler) - but for my understanding multithreading would enable us run two or more long running processes simultaneously and the UI would still be responsiveness. The AVM simply can't handle that!

"At this time, the allowable uses of the Bridge are restricted to developing or deploying Microsoft .NET Winforms User Interfaces for business applications using OpenEdge products, and for one-way usage of AVM calling the CLR (and not vice versa).   


Any use of the Bridge other than as set forth in the previous paragraph is prohibited.  Additionally, the Bridge may not be used for multi-threaded processes."

I'm with you that it would be nice to have a multi threaded client some time soon (other things are higher on my personal priorities list). But I think for anybody using the GUI for .NET today it's important to know it's limits.

Posted by Thomas Mercer-Hursh on 17-Jun-2009 11:48

On my priority list, it is a *lot* higher than "nice to have" ... and not because of UI, although it would be good there too, but for writing services.

This thread is closed