Subject | Reminder about using IBO in a multi-threading environment |
---|---|
Author | kylixguru |
Post date | 2011-12-16T16:53:44Z |
I would like to remind everyone about some specific aspects of how to use IBO properly in a multi-threaded environment.
You must use a TIB_Session component for each active thread because all TIB_Connection, TIB_Transaction, TIB_Statement, TIB_Dataset, etc. components are kept in lists inside of the session and there is a certain level of processing that occurs within the scope of all components connected to a session. Therefore, by taking control of your session and all the related components you are able to isolate their activity from one another. Each session you create provides the basis for a totally distinct grouping of data access components.
If you are using a data module to hold all of your data access components and then your application will use instances of that data module for your thread activity then simply dropping a TIB_Session component on that form/module will be sufficient. It automatically will position itself in the creation order to precede all sibling IBO data access components. This way, all of the data access components will automatically associate themselves to that session. I agree this feature imposes the need to have separate data modules for each thread's context.
Another common method of doing multi-threading is to simply do it in code with custom classes. Objects are created, used and then destroyed when done. When doing this, you should always create an instance of TIB_Session first so that as other data access components are created they can be directly associated with your session. In this way, you safely isolate all activities of the new data access component instances within that threads scope/context. The best way to do this is to use the TIB_Session instance as the owner of the data access components. By doing this, it will immediately create the instance and associate it to the session without going out and looking globally for a session instance to make use of.
If you have child data modules that are owned by a main data module then the data access components will automatically make use of the session instance in the owning main data module. This is because when the instances are created in the child data module and there isn't a TIB_Session instance on that module, IBO will look up the chain of ownership for a parent form and look at that form's instances. If it finds a TIB_Session instance on the parent's form, then that child module's data access component instances will automatically associate with that session instance. So, the "rule of thumb" (so to speak) with IBO and multi-threading is to realize that ownership has direct implications upon resolving sessions.
It seems very popular/common to give a NIL owner to create connections, transactions, datasets, etc. but this leaves IBO in the awkward position of not knowing how to resolve which session instance that data access component will associate with. This leaves it open to use default mechanisms to try and resolve the session which could have ambiguous or unpredictable results. I have also given the ability to associate a data access component to a session instance explicitly with the IB_Session property. It should be possible to create your instances with a NIL owner if you really want to and then you just manually assign the session instance. This is something that *should* work safely but you should keep in mind doing it this way has the new instance temporarily integrated into the global and ambiguous default mechanisms which could open up some vulnerability.
In short, it is much better if the creation of the data access component instance knows right from the start how to directly associate itself to the session so that there won't be thread activity out in a global setting trying to figure things out.
If the session context is made immediately available in the constructor or there is an Owner hierarchy to examine to find the intended session, this is the way to go.
I hope this helps those trying to make use of IBO in a multi-threading environment.
Kind regards,
Jason Wharton
www.ibobjects.com
You must use a TIB_Session component for each active thread because all TIB_Connection, TIB_Transaction, TIB_Statement, TIB_Dataset, etc. components are kept in lists inside of the session and there is a certain level of processing that occurs within the scope of all components connected to a session. Therefore, by taking control of your session and all the related components you are able to isolate their activity from one another. Each session you create provides the basis for a totally distinct grouping of data access components.
If you are using a data module to hold all of your data access components and then your application will use instances of that data module for your thread activity then simply dropping a TIB_Session component on that form/module will be sufficient. It automatically will position itself in the creation order to precede all sibling IBO data access components. This way, all of the data access components will automatically associate themselves to that session. I agree this feature imposes the need to have separate data modules for each thread's context.
Another common method of doing multi-threading is to simply do it in code with custom classes. Objects are created, used and then destroyed when done. When doing this, you should always create an instance of TIB_Session first so that as other data access components are created they can be directly associated with your session. In this way, you safely isolate all activities of the new data access component instances within that threads scope/context. The best way to do this is to use the TIB_Session instance as the owner of the data access components. By doing this, it will immediately create the instance and associate it to the session without going out and looking globally for a session instance to make use of.
If you have child data modules that are owned by a main data module then the data access components will automatically make use of the session instance in the owning main data module. This is because when the instances are created in the child data module and there isn't a TIB_Session instance on that module, IBO will look up the chain of ownership for a parent form and look at that form's instances. If it finds a TIB_Session instance on the parent's form, then that child module's data access component instances will automatically associate with that session instance. So, the "rule of thumb" (so to speak) with IBO and multi-threading is to realize that ownership has direct implications upon resolving sessions.
It seems very popular/common to give a NIL owner to create connections, transactions, datasets, etc. but this leaves IBO in the awkward position of not knowing how to resolve which session instance that data access component will associate with. This leaves it open to use default mechanisms to try and resolve the session which could have ambiguous or unpredictable results. I have also given the ability to associate a data access component to a session instance explicitly with the IB_Session property. It should be possible to create your instances with a NIL owner if you really want to and then you just manually assign the session instance. This is something that *should* work safely but you should keep in mind doing it this way has the new instance temporarily integrated into the global and ambiguous default mechanisms which could open up some vulnerability.
In short, it is much better if the creation of the data access component instance knows right from the start how to directly associate itself to the session so that there won't be thread activity out in a global setting trying to figure things out.
If the session context is made immediately available in the constructor or there is an Owner hierarchy to examine to find the intended session, this is the way to go.
I hope this helps those trying to make use of IBO in a multi-threading environment.
Kind regards,
Jason Wharton
www.ibobjects.com