
Hello, All I have finished implementation of Lwsync library, which contains two patterns to organize synchronization on concurrent environment. I would like to propose to include this library into Boost. Lwsync provides critical resource and monitor patterns. Critical resource synchronizes all accesses to specific resource and automatically invokes locking and unlocking methods before and after each access. Monitor pattern is a kind of critical resource which not only synchronizes all accesses but also allows one to wait until resource becomes in defined state. One can use Lwsync patterns like this: Example 1: typedef critical_resource<std::vector<int> > critical_vector_t; critical_vector_t critical_vector; critical_resource<std::ostream&> sync_cout(std::cout); critical_vector.access()->push_back(10); { critical_vector_t::const_accessor vector_access = critical_vector; for(size_t i = 0; i < vector_access->size(); ++i) *sync_cout.access() << "Index : " << i << ", Data : " << (*vector_access)[i] << std::endl; } Example 2: typedef monitor<std::vector<int> > monitor_vector_t; bool is_not_empty(const std::vector<int>& test_vector) { return !test_vector.empty(); } monitor_vector_t monitor_vector; thread 1: { monitor_vector_t::accessor vector_access = monitor_vector.wait_for(is_not_empty); // Do something with non-empty vector here. } thread 2: monitor_vector.access()->push_back(10); Lwsync library can be mapped on any threading facilities and by default it is mapped on Boost.Thread ones. Is there any interest in this library? --- With respect, Vladimir Frolov

Vladimir Frolov wrote:
Hello, All
I have finished implementation of Lwsync library, which contains two patterns to organize synchronization on concurrent environment. I would like to propose to include this library into Boost.
Lwsync library can be mapped on any threading facilities and by default it is mapped on Boost.Thread ones.
Is there any interest in this library?
Although we have a quite a few concurrency libraries in the vault and in development, I always think that each one provides an interesting perspective. Just one comment about yours:
Example 2: typedef monitor<std::vector<int> > monitor_vector_t; bool is_not_empty(const std::vector<int>& test_vector) { return !test_vector.empty(); }
monitor_vector_t monitor_vector;
thread 1: { monitor_vector_t::accessor vector_access = monitor_vector.wait_for(is_not_empty); // Do something with non-empty vector here. }
thread 2: monitor_vector.access()->push_back(10);
I think wait_for() should return a lock object on the monitor's resource. Otherwise, the vector could be emptied again before thread 1 gets to execute anything. (Only each individual access is locked in your system.) Generally, there should be a way to obtain a lock for a resource that outlasts a single call. If this is implemented as I guess it is, you might also suffer from the not clearly defined temporary destruction semantics. Sebastian Redl

Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
I think wait_for() should return a lock object on the monitor's resource. Otherwise, the vector could be emptied again before thread 1 gets to execute anything. (Only each individual access is locked in your system.) Generally, there should be a way to obtain a lock for a resource that outlasts a single call. If this is implemented as I guess it is, you might also suffer from the not clearly defined temporary destruction semantics.
Lwsync patterns provides accessors objects to access resource. One can read/change some resource only via its accessors. Both access() and wait_for() methods returns an accessors so that one cannot change resource until this accessor will be destryed. For example: { monitor_vector_t::accessor vector_access = monitor_vector.wait_for(is_not_empty); // monitor_vector cannot be changed until object vector_access is exists. for(size_t i = 0; i < vector_access->size(); ++i) *sync_cout.access() << "Index : " << i << ", Data : " << (*vector_access)[i] << std::endl; } To obtain the access to resource that outlasts a single call you have to use automaitc accessor objects (Like in my example 1). If you want to make a single call you can use temporary objects: monitor_vector.access()->push_back(10); You can even escalate access to critical resource from within scope of you own routine. Like this: monitor_vector_t::accessor some_vector_action() { monitor_vector_t::accessor vec_access = monitor_vector; vec_access->puch_back(10); return vec_access; // Access is escalated from within a some_vector_action() scope // So that one can make some other action with vector before it becomes // unlocked. } { monitor_vector_t::accessor vec_access = some_vector_action(); vec_access->puch_back(20); // There are guarantee that Elements 10 and 20 will be placed in // vector sequentially. // Any other action with vector cannot be processed between those two // push_back's. } Or use even dynamic objects to control lifetime of access manually. Unfortunatly I hear nothing about not clearly defined temporary destruction semantics problem. All compilers I am able to test (VC7.1, VC8.0) destroy temporary objects exacly after experession where it was created. Could you please refer me to description of this problem? --- With respect, Vladimir Frolov

Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
If this is implemented as I guess it is, you might also suffer from the not clearly defined temporary destruction semantics.
I think that concept of accessors will work correctly with any optimization of temporary object returning. In case if no optimization applied copy constructor will be invoked (maybe even several times) but recursive mutex will handle this situation. In case if any optimization applied compiler will destroy any object after it becomes inaccessible (just after expression where temporary object is created and used). So we have only two kinds of situations: either we have some accessor object (it can be temporary, automatic, dynamic or any other) resource is locked and we can access it, or we have no accessor objects, resource is unlocked and we can access it only by creation accessor. Am I right or it is possible on a single compiler that some object destroys not exactly after it becomes inaccessible? --- With respect, Vladimir Frolov
participants (2)
-
Sebastian Redl
-
Vladimir Frolov