B4A Library Threading library

This library lets you run Basic4android Subs on separate threads to the main GUI thread. It also contains a Lock (semaphore) object that can be used for resource access arbitration and thread synchronisation.

Included is also an enhanced Exception object to give more information on any Exception caught. This can also rethrow those caught Exceptions and can create new Exceptions to throw.

EDIT :- Version 1.1 posted. See post #13 for details.
 

Attachments

  • Threading1.1.zip
    19.2 KB · Views: 7,208
Last edited:

westingenieria

Active Member
Licensed User
Longtime User
Yes, i know and thank you for that.. i only want to know if there is a problem with start a Thread every time with a timer...

Thank you again
 

agraham

Expert
Licensed User
Longtime User
The Threading library dates from early in Basic4android history when there was no other asynchronous mechanism available. Nowadays good practice is for libraries to provide the asynchronism when necessary.

Starting a Thread is an expensive operation whereas Ba.SubmitRunnable re-uses existing Threads from a pool of threads for efficiency. The only real use for a thread should be for a long running operation that loops or waits and is not expected to terminate often.

You can start a Thread in a Timer but only the main thread can access GUI elements. You get errors as you have found if you do it in a Thread, or a submitted Runnable. This is one of the reasons RaiseEventFromDifferentThread exists.
 

Melchor99

Member
Licensed User
Longtime User
Hi, I'm coding a game. It's a soccer manager game which launch 4 threads in some parts of the game in order to update some division leagues.

Each thread perform some updates and inserts into a SQLLite DB. The program and threads execution works fine about on 75% of the times, but on 25% the threads are destroyed, it seems that due to locks in DB but i'm not sure. I'm a bit desperate because after some weeks I can't find the way to solve it :-(

These are the dumps.

DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1 WAIT
| group="main" sCount=1 dsCount=0 obj=0x40022180 self=0xce68
| sysTid=14091 nice=0 sched=0/0 cgrp=default handle=-1345002400
at java.lang.Object.wait(Native Method)
- waiting on <0x40022218> (a java.lang.VMThread)
at java.lang.Thread.parkFor(Thread.java:1424)
at java.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
at sun.misc.Unsafe.park(Unsafe.java:337)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:808)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:841)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1171)
at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:378)
at android.database.sqlite.SQLiteProgram.close(SQLiteProgram.java:294)
at android.database.sqlite.SQLiteQuery.close(SQLiteQuery.java:136)
at android.database.sqlite.SQLiteCursor.close(SQLiteCursor.java:505)
at anywheresoftware.b4a.sql.SQL.ExecQuerySingleResult2(SQL.java:230)
at anywheresoftware.b4a.sql.SQL.ExecQuerySingleResult(SQL.java:211)
at com.ibeSoccer.juego._timer1_tick(juego.java:3907)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:167)
at anywheresoftware.b4a.objects.Timer$TickTack.run(Timer.java:103)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3835)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)

"Thread4" daemon prio=5 tid=12 NATIVE
| group="main" sCount=1 dsCount=0 obj=0x4054cde8 self=0x27f280
| sysTid=14104 nice=0 sched=0/0 cgrp=default handle=2618640
at android.database.sqlite.SQLiteDatabase.native_execSQL(Native Method)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1763)
at anywheresoftware.b4a.sql.SQL.ExecNonQuery(SQL.java:66)
at com.ibeSoccer.juego._juegajornadaligaoculto(juego.java:2088)
at com.ibeSoccer.juego._juegaotrasligasext2(juego.java:2558)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.agraham.threading.Threading$1.run(Threading.java:216)
at java.lang.Thread.run(Thread.java:1019)

"Thread3" daemon prio=5 tid=11 WAIT
| group="main" sCount=1 dsCount=0 obj=0x4058f968 self=0x2913a0
| sysTid=14103 nice=0 sched=0/0 cgrp=default handle=1785536
at java.lang.Object.wait(Native Method)
- waiting on <0x4058fa90> (a java.lang.VMThread)
at java.lang.Thread.parkFor(Thread.java:1424)
at java.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
at sun.misc.Unsafe.park(Unsafe.java:337)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:808)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:841)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1171)
at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:378)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1757)
at anywheresoftware.b4a.sql.SQL.ExecNonQuery(SQL.java:66)
at com.ibeSoccer.juego._juegajornadaligaoculto(juego.java:2131)
at com.ibeSoccer.juego._juegaotrasligasesp2(juego.java:2484)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.agraham.threading.Threading$1.run(Threading.java:216)
at java.lang.Thread.run(Thread.java:1019)

"Thread2" daemon prio=5 tid=10 WAIT
| group="main" sCount=1 dsCount=0 obj=0x405bc468 self=0x28ef00
| sysTid=14102 nice=0 sched=0/0 cgrp=default handle=2582912
at java.lang.Object.wait(Native Method)
- waiting on <0x405bc578> (a java.lang.VMThread)
at java.lang.Thread.parkFor(Thread.java:1424)
at java.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
at sun.misc.Unsafe.park(Unsafe.java:337)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:808)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:841)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1171)
at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:378)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1757)
at anywheresoftware.b4a.sql.SQL.ExecNonQuery(SQL.java:66)
at com.ibeSoccer.juego._juegajornadaligaoculto(juego.java:2119)
at com.ibeSoccer.juego._juegaotrasligasext1(juego.java:2521)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.agraham.threading.Threading$1.run(Threading.java:216)
at java.lang.Thread.run(Thread.java:1019)

"Thread1" daemon prio=5 tid=9 WAIT
| group="main" sCount=1 dsCount=0 obj=0x405201a0 self=0x28edc8
| sysTid=14101 nice=0 sched=0/0 cgrp=default handle=705624
at java.lang.Object.wait(Native Method)
- waiting on <0x40520320> (a java.lang.VMThread)
at java.lang.Thread.parkFor(Thread.java:1424)
at java.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
at sun.misc.Unsafe.park(Unsafe.java:337)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:808)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:841)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1171)
at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:378)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1757)
at anywheresoftware.b4a.sql.SQL.ExecNonQuery(SQL.java:66)
at com.ibeSoccer.juego._juegajornadaligaoculto(juego.java:2127)
at com.ibeSoccer.juego._juegaotrasligasesp1(juego.java:2447)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.agraham.threading.Threading$1.run(Threading.java:216)
at java.lang.Thread.run(Thread.java:1019)

"Binder Thread #2" prio=5 tid=8 NATIVE
| group="main" sCount=1 dsCount=0 obj=0x40516c90 self=0xec0d8
| sysTid=14098 nice=0 sched=0/0 cgrp=default handle=1152560
at dalvik.system.NativeStart.run(Native Method)

"Binder Thread #1" prio=5 tid=7 NATIVE
| group="main" sCount=1 dsCount=0 obj=0x40513ac0 self=0xf8ce8
| sysTid=14097 nice=0 sched=0/0 cgrp=default handle=1152096
at dalvik.system.NativeStart.run(Native Method)

"Compiler" daemon prio=5 tid=6 VMWAIT
| group="system" sCount=1 dsCount=0 obj=0x40512d00 self=0xf8bb0
| sysTid=14096 nice=0 sched=0/0 cgrp=default handle=1151912
at dalvik.system.NativeStart.run(Native Method)

"JDWP" daemon prio=5 tid=5 VMWAIT
| group="system" sCount=1 dsCount=0 obj=0x40512c50 self=0xeb158
| sysTid=14095 nice=0 sched=0/0 cgrp=default handle=978304
at dalvik.system.NativeStart.run(Native Method)

"Signal Catcher" daemon prio=5 tid=4 RUNNABLE
| group="system" sCount=0 dsCount=0 obj=0x40512b90 self=0xad4d0
| sysTid=14094 nice=0 sched=0/0 cgrp=default handle=1151544
at dalvik.system.NativeStart.run(Native Method)

"GC" daemon prio=5 tid=3 VMWAIT
| group="system" sCount=1 dsCount=0 obj=0x40512ae8 self=0xf1178
| sysTid=14093 nice=0 sched=0/0 cgrp=default handle=524104
at dalvik.system.NativeStart.run(Native Method)

"HeapWorker" daemon prio=5 tid=2 VMWAIT
| group="system" sCount=1 dsCount=0 obj=0x40512a30 self=0xacdb0
| sysTid=14092 nice=0 sched=0/0 cgrp=default handle=626536
at dalvik.system.NativeStart.run(Native Method)


Any idea on what I'm doing in the wrong way?

For more information, there's not begin or commit transact in database accesses of the threads.

Thanks in advance!

Regards
 
Last edited:

Melchor99

Member
Licensed User
Longtime User
First of all, thanks for your feedback.

I'm going to try next sequence:

- Open only one thread
- In the thread prepare all the updates/inserts and queue them on AddNonQueryToBatch
- After this, in the same unique thread ExecNonQueryBatch
- In the main program , catch with a variable the end SQL_NonQueryComplete and when success will be OK, enable a button to continue the operations.

I'll provide feedback with the results (when I'll get some time to do it), I'll hope it not take too much time as now with 4 threads to complete the operation.

Thanks again.
 

java4never

Member
Licensed User
Longtime User
Hi!

I’m having some problems with this library.
When I load the example project, I get this java exception while running it:
"Sub ... not found."
Is there anything I’m missing?

Device: Nexus 7, Android 4.2.2
B4A Version: 2.52

Thanks in advance

David W.
 

agraham

Expert
Licensed User
Longtime User
Downloads and runs fine for me.

Always post the complete error message - which Sub is not found?

Always look in the Logs tab of the IDE when an error occurs. You will usually see the reason for the error and a stack trace. Right click to copy the logs and post the result if you don't understand it.

The stack trace includes a Java line number that you can correlate with your code by looking at the Java code under the Ojects/src/... folder using a line numbering editor like Notepad++. Your Basic code is included in the Java as comments.
 

java4never

Member
Licensed User
Longtime User
Solved

Thanks agraham for your help, but the problem has solved itself:sign0161:
No idea why, but i tried your example project again today, and all worked fine!
Then I tried my code and surprise surprise, it worked, too!:sign0060:
Why not every problem is solving itself?;)

regards
David W.
 

Melchor99

Member
Licensed User
Longtime User
Hi,

After some tests I have replace the 4 threads of my App by async non queries batch sentences in my program. I've notice that async instructions take a bit more time to be completed as doing the same with threads.

After some months, my experience is that using threads, if you access during execution to DB and press home (Pause the application) the threads seems to be destroyed (I've test with one and four threads). I can't find a way to include DB sentences in a thread and pressing the home button make that threads don't be destroyed.

I think, finally I'm going to use asyn sentences to finish my program.

Thanks for your help and for threading and async libraries which have helped me to learn a bit more.

Regards.
 

yttrium

Active Member
Licensed User
Longtime User
Threading needs to be updated to support obfuscation. As it stands now, if you try to compile an app using Release (obfuscated), the app will crash as soon as a thread is called, because while you direct the thread worker to a sub using a string name, a sub by that name no longer exists (its name was obfuscated). The string value isn't obfuscated to match, however, so it crashes the app.

I seriously have no idea how to handle this without changing Thread.Start to take a sub instead of a string.
 

agraham

Expert
Licensed User
Longtime User
The library knows nothing about obfuscation, and a Sub is not an object so cannot be passed as a parameter. You need to add an underscore to the called Subs name and it will not be obfuscated. You will find a similar 'feature' if you use CallSub with the called Sub name in a variable and the cure is the same.
 

yttrium

Active Member
Licensed User
Longtime User
The library knows nothing about obfuscation, and a Sub is not an object so cannot be passed as a parameter. You need to add an underscore to the called Subs name and it will not be obfuscated. You will find a similar 'feature' if you use CallSub with the called Sub name in a variable and the cure is the same.
Alright. Meh, I just won't obfuscate, it isn't that big of a deal for now.
 

kiki78

Active Member
Licensed User
Longtime User
Hi agraham,

I have strange error.
I join demo project to demonstrate it.
In debug mode, if you execute it, press Start then Stop you obtain following error.

B4X:
ThFunc is started
ThFunc is started
thclass_thstop (B4A line: 96)
End Sub
thclass_thstop (B4A line: 96)
End Sub
java.lang.IndexOutOfBoundsException: index 3
   at java.util.concurrent.atomic.AtomicIntegerArray.checkedByteOffset(AtomicIntegerArray.java:36)
   at java.util.concurrent.atomic.AtomicIntegerArray.get(AtomicIntegerArray.java:83)
   at anywheresoftware.b4a.debug.Debug.ShouldStop(Debug.java:222)
   at b4a.example.thclass._thstop(thclass.java:276)
   at b4a.example.main._btstop_click(main.java:327)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:157)
   at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
   at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:63)
   at android.view.View.performClick(View.java:4232)
   at android.view.View$PerformClick.run(View.java:17318)
   at android.os.Handler.handleCallback(Handler.java:615)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:4921)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
   at dalvik.system.NativeStart.main(Native Method)
java.lang.IndexOutOfBoundsException: index 3
   at java.util.concurrent.atomic.AtomicIntegerArray.checkedByteOffset(AtomicIntegerArray.java:36)
   at java.util.concurrent.atomic.AtomicIntegerArray.get(AtomicIntegerArray.java:83)
   at anywheresoftware.b4a.debug.Debug.ShouldStop(Debug.java:222)
   at b4a.example.thclass._thstop(thclass.java:276)
   at b4a.example.main._btstop_click(main.java:327)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:157)
   at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
   at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:63)
   at android.view.View.performClick(View.java:4232)
   at android.view.View$PerformClick.run(View.java:17318)
   at android.os.Handler.handleCallback(Handler.java:615)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:4921)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
   at dalvik.system.NativeStart.main(Native Method)

If you remove any blank line in ThClass between line 29 and 89 and execute, no error.
Blank line are for illustration, but this can be any code.
Only line number of function seems to be important.


I take lot of hours to isolate it in my project.
I never found rational explanation.

May you help me ?

Regards
 

Attachments

  • TestBAThread.zip
    8.3 KB · Views: 245

kiki78

Active Member
Licensed User
Longtime User
Hi Erel,

I communicate with custom USB Device. This device use 1 In/Out endpoint for command and 2 In endpoint to transfer different data flow to Host.
I use synchronous transaction (BulkTransfert) in loop in 2 thread to get this data flow.
 

kiki78

Active Member
Licensed User
Longtime User
Hello Erel,

You write "the debugger cannot be used with this library".

Must I understand I can't run in debug mode, in anyway, if I use this library ?
I previously experiment to put breakpoint inside threaded method and see that this doesn't work.
But I use threading in BA4 before and have not problem to run in debug mode.
The problem I report in #53 is really strange. The line number of method seems to be the problem.

Sorry to insist but, have you way to use thread in BA4?
Should I abandon the use of debugger ?
Must I need to put threaded method in class of external library ? Is it sufficient ?

Thank you for your valuable advice.

Best Regards
 

kiki78

Active Member
Licensed User
Longtime User
Thank you Erel,

I rewrite my class with asynchronous USB method and it seems to work fine.

But my questions in previous message remain valid.
All data I collect need to be process in pseudo-realtime with intensive math calculation.
I expect to put this process in independent thread to improve use of multicore processor.
I already intensively use thread on VB.NET for similar application, with really interesting power gain (around x3 on quad core) .
If I want to use threading and simply adapt my code from VB.NET to B4A, can I simply put it in class in my code or do you recommend to compile it in library. Is this sufficient to avoid problem with debugger, or may I need to rewrite it in Java ?
 
Top