tag:blogger.com,1999:blog-3285677929777490656.post1667234949447296778..comments2023-10-31T13:16:01.375+03:00Comments on Open CASCADE notes: Open CASCADE Handles. Let's handle'em. Part 3Roman Lyginhttp://www.blogger.com/profile/18338419158437898791noreply@blogger.comBlogger15125tag:blogger.com,1999:blog-3285677929777490656.post-22827615292022098942008-12-01T17:55:00.000+03:002008-12-01T17:55:00.000+03:00The comment itself is a bit misleading. You need t...The comment itself is a bit misleading. You need to choose between object manipulated by value and one by handle in the same way as if you chose between an object and a pointer to an object. If you need to share a data between several users you choose in favor of handle type. Another advantage of handle is that you do not need to worry about memory leaks, the memory will be freed up as soon as the last usage of underlying object will be terminated.<BR/>Life time is a period of time between object creation and its destruction. The following three objects will have the same life time, limited by a scope, despite one is manipulated by value and two others are by handle:<BR/>{<BR/>gp_Pnt aP1 (0, 0, 0);<BR/>Handle(Geom_CartesianPoint) aP2 = new Geom_CartesianPoint (aP1);<BR/>Handle(Geom_CartesianPoint) aP3 = new Geom_CartesianPoint (1, 1, 1);<BR/>}Roman Lyginhttps://www.blogger.com/profile/18338419158437898791noreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-33253491562533489122008-11-30T16:18:00.000+03:002008-11-30T16:18:00.000+03:00Hello Roman,First, thanck you very much for the hi...Hello Roman,<BR/><BR/>First, thanck you very much for the high quality articles you share in this blog. <BR/><BR/>Second, I have a question related to handles that come from OCC "get started" page. Here are a few lines extracted from OCC web site:<BR/>"""<BR/>To choose the best class for this application, consider the following:<BR/><BR/>- gp_Pnt is manipulated by value. Like all objects of its kind, it will have a limited life time.<BR/>- Geom_CartesianPoint is manipulated by handle and may have multiple references and a long life time.<BR/>"""<BR/><BR/>What is the "life time" concept expressed in this chapter? How can it be measured?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-6639518248422621162008-11-26T20:20:00.000+03:002008-11-26T20:20:00.000+03:00Hi Pawel,Indeed, (1) and (3) may look similar but ...Hi Pawel,<BR/><BR/>Indeed, (1) and (3) may look similar but I intentionally separated them. (1) is still a preferred way (as it's safer and let you double-check the type) and is recommended if you are not sure if casting is always unambiguous, or you need to cast into several types, for instance:<BR/><BR/>Handle(OCC_UT_Employee) anEmployee = Handle(OCC_UT_Employee)::DownCast (theEmployee);<BR/>if (!anEmployee.IsNull() {<BR/>...<BR/>} else {<BR/>Handle(OCC_UT_Manager) aManager = Handle(OCC_UT_Manager)::DownCast (theEmployee);<BR/>if (!aManager.IsNull()) {<BR/> //manager-specific processing in a loop<BR/>...<BR/><BR/>(3) bears some risk but is the fast way when performance is critical. Imagine if BRep_Tool::Surface() would be re-written as follows:<BR/><BR/>const Handle(Geom_Surface)& BRep_Tool::Surface(const TopoDS_Face& F,<BR/> TopLoc_Location& L)<BR/>{<BR/> Handle(BRep_TFace) TF = Handle(BRep_TFace)::DownCast (F.TShape());<BR/>// Handle(BRep_TFace)& TF = *((Handle(BRep_TFace)*) &F.TShape());<BR/> L = F.Location() * TF->Location();<BR/> return TF->Surface();<BR/>}<BR/>Performance would be awful.<BR/><BR/>Hope this clarifies.Roman Lyginhttps://www.blogger.com/profile/18338419158437898791noreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-24262032160258748422008-11-25T01:22:00.000+03:002008-11-25T01:22:00.000+03:00Hi Roman,first of all thanks for the article!Maybe...Hi Roman,<BR/><BR/>first of all thanks for the article!<BR/><BR/>Maybe it's a stupid question but I don't get the difference between issues (1) and (3). Using the cast operator is quite clear. But I didn't really get what are 'critical situations' and why they influence the performance. Could you please comment on that?<BR/><BR/>Thanks<BR/>PawelAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-68570961225478837152008-11-23T18:08:00.000+03:002008-11-23T18:08:00.000+03:00Hi Denis,Valid comments. Legacy is way too impacti...Hi Denis,<BR/>Valid comments. Legacy is way too impacting OCC code. WOK and CDL are first victims I would sacrifice. On the other hand, there can be commercial customers (at least there were) under maintenance contracts, and the company may have some obligations. But I think this can be solved. Well, at least, they could be removed from the distribution. Fortunately, you don't have to study WOK or CDL, anyway.<BR/>As far as smart pointers and collections are concerned, I also agree this should be on todo list.Roman Lyginhttps://www.blogger.com/profile/18338419158437898791noreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-73415815676465702492008-11-22T15:55:00.000+03:002008-11-22T15:55:00.000+03:00Hi Roman,IMHO the main problem when programming wi...Hi Roman,<BR/><BR/>IMHO the main problem when programming with OCC is not the lack of documentation but the wheel being reinvented everywhere. Okay, there are historical reasons, but why would anyone want to become an expert with Handle today when smart pointers are being put into C++ standard?<BR/>This is even more true for STL or templates, OCC would be much friendlier for developers if code base did use existing state of the art technology.<BR/>The learning curve is way too steep, I never invested in learning CDL because I use OCC code occasionnally, and do not understand why I should learn CDL and WOK instead of using plain C++ within my favourite IDE. I hope that OCC devs will some day reconsider their achievement of rewriting everything from scratch ;-)<BR/>In the meantime, your articles are definitely useful, thanks!Unknownhttps://www.blogger.com/profile/09650874269830633223noreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-5344248443236436642008-11-22T13:09:00.000+03:002008-11-22T13:09:00.000+03:00Folks,Yes, a correct statement would be to state t...Folks,<BR/><BR/>Yes, a correct statement would be to state that Handle_Standard_Transient (as well as its descendants) itself *is* thread-safe as its entity field never changes (i.e. is only read). However, Standard_Transient (which is pointed to by Handle_Standard_Transient.entity) is not safe. Therefore any attempt to access its field with GetRefCount() to without a protection creates a data race. This occurs, for instance, if you copy a handle to another in one thread while accessing its ref count in another.<BR/><BR/>And, of course, MMGT_REENTRANT=1 is a must for multi-threaded apps. Otherwise, even simple copies of handles creates a data race as ++ operator is not atomic.Roman Lyginhttps://www.blogger.com/profile/18338419158437898791noreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-12419003584340823462008-11-21T19:23:00.000+03:002008-11-21T19:23:00.000+03:00Hello Andrey, that's good news, so it's thread sa...Hello Andrey,<BR/> that's good news, so it's thread safe now since release 6.3. (I saw you're the one how worked on the atomic operation.)<BR/><BR/>FrancoisAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-55946676965688958662008-11-21T18:25:00.000+03:002008-11-21T18:25:00.000+03:00Hello Francois,In fact, manipulations with referen...Hello Francois,<BR/><BR/>In fact, manipulations with reference counter have been protected in OCC 6.3.0 using atomic operations. I take this chance to thank you for pointing out this issue on OCC forum.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-25727887436685295762008-11-21T16:24:00.000+03:002008-11-21T16:24:00.000+03:00Thanks, Francois.Yes, I think Qt experience would ...Thanks, Francois.<BR/><BR/>Yes, I think Qt experience would be helpful for OCC as well. I once read this article - http://doc.trolltech.com/qq/qq14-threading.html - and recently re-read it. Perhaps OCC could benefit both for handles and Standard_Mutex.Roman Lyginhttps://www.blogger.com/profile/18338419158437898791noreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-62333174117862885812008-11-21T16:12:00.000+03:002008-11-21T16:12:00.000+03:00Hello all,About thread safety when using an Handle...Hello all,<BR/>About thread safety when using an Handle, the Handle itself is not thread safe, because the reference count is not protected. If you do something like that inside two different thread that use the same original Handle, you might have problem:<BR/><BR/>Handle(OCC_UT_Id) receivedHandle; <BR/>Handle(OCC_UT_Id) copyOfTheReceivedHandle=receivedHandle; // here you might have a problem if two thread do this operation at the same time<BR/><BR/>So, just a simple assignment of this kind will cause a problem, because the ref count might or might not be incremented correctly due to concurrent access to it. And this kind of assignment could append all the time, when you pass a Handle by value, return a Handle by value, do a DownCast, ...<BR/><BR/> <BR/>We have had problem with that and we solved the problem by building our own smart pointer based on Qt QSharedDataPointer. The smart pointer used thread safe ref count increment/decrement using atomic operation (which are much faster than using a mutex to protect the ref count).<BR/><BR/>So this solve the assignment of smart pointer to other smart pointer. If you want to access/modify the data that the pointer point to, you still need a way to serialize the access (mutex,...)<BR/><BR/>Francois.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-32670440537400409192008-11-21T15:27:00.000+03:002008-11-21T15:27:00.000+03:00Very nice article. In fact, I was always tempted t...Very nice article. In fact, I was always tempted to do a direct casting in some cases, but I always had my doubts about it, even when I was sure the object was of that specific type. I'll keep that trick in mind.<BR/><BR/>I hope you have the inspiration to continue writing more articles like these, each one slowly delving deeper into OCC.Cenizahttps://www.blogger.com/profile/13711461089780429660noreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-216794809384906302008-11-21T14:16:00.000+03:002008-11-21T14:16:00.000+03:00Hi Andrey,Thanks for support and great comments.1....Hi Andrey,<BR/><BR/>Thanks for support and great comments.<BR/><BR/>1. Interesting, I didn't know that. But not sure if I fully understand the use case. Can you post an example ?<BR/><BR/>2. Yes, sorry for confusion. By thread-safety I meant that the same object can be safely used (read-write) in different threads. This is not the case for Handle. Though it is *re-entrant*, i.e. different objects can safely live in different threads. I adopted Qt terminology which says:<BR/><I><BR/>* A reentrant function can be called simultaneously by multiple threads provided that each invocation of the function references unique data.<BR/>* A thread-safe function can be called simultaneously by multiple threads when each invocation references shared data. All access to the shared data is serialized.<BR/><BR/>By extension, a class is said to be reentrant if each and every one of its functions can be called simultaneously by multiple threads on different instances of the class. Similarly, the class is said to be thread-safe if the functions can be called by different threads on the same instance.</I><BR/><BR/>Yes, and, of course, like you say, simultaneous reading from multiple threads is fine.Roman Lyginhttps://www.blogger.com/profile/18338419158437898791noreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-8429756672805221662008-11-21T13:54:00.000+03:002008-11-21T13:54:00.000+03:00Nice, I am waiting for the next entry :)Nice, I am waiting for the next entry :)Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3285677929777490656.post-15798800608497012012008-11-21T13:40:00.000+03:002008-11-21T13:40:00.000+03:00Hello Roman,You have started great thing! IMHO OCC...Hello Roman,<BR/><BR/>You have started great thing! IMHO OCC badly lacks this kind of activity - someone to share his knowledge in the form of articles. <BR/><BR/>Now copule of comments on problems you highlighted:<BR/><BR/>1. There is some utility of having UndefinedHandleAddress not equal to zero. I have seen a few cases when one static variable is constructed by reference to another static variable which might be not-yet-initialized at the moment. Now in such case you get immediately Access Violation signal at null address; if UndefinedHandleAddress were null this problem might remain unnoticed.<BR/><BR/>One idea (thanks to AGV) is to set this value to 0x01 -- this address should be bad for all platforms. Though not completely sure...<BR/><BR/>2. IMHO, your statement that Handles are not yet thread-safe might be confusing. Actually, they are safe for handling one object accessed from multiple threads, provided that each thread uses either its own Handle or common constant one; but for sure you need to ensure that you do not use and modify single Handle object concurrently. This is just the same as with any other simple type.Anonymousnoreply@blogger.com