Opened 8 years ago

Closed 8 years ago

#10128 closed Feature Requests (wontfix)

Use lockable_adapter with const objects or const members

Reported by: anonymous Owned by: viboes
Milestone: Component: thread
Version: Boost 1.54.0 Severity: Problem
Keywords: Cc:

Description (last modified by viboes)

I would like to use lockable_adapter pattern with const objects. Usually, we need to access in protected mode to one const object (read some value).

We have a compiler error when we connect unique_lock and one derived class from lockable_adapter and the object is const.

int func(const Class1& obj)
{
    boost::unique_lock<Class1> lock(obj);
    //boost::unique_lock<Class1> lock(const_cast<Class1&>(obj));
    return obj.get();
}

->

error C2664: 'boost::unique_lock<Mutex>::unique_lock(boost::upgrade_lock<Mutex> &)' : no se puede convertir el parámetro 1 de 'const Class1' a 'boost::upgrade_lock<Mutex> &'

The solution for us is rewrite the sentence with one const_cast<Class1> -> boost::unique_lock<Class1> lock(const_cast<Class1&>(obj));

We are using Visual C++ 2010

Best regards

Attachments (1)

example_lock_constObject.cpp (821 bytes ) - added by anonymous 8 years ago.
Error example

Download all attachments as: .zip

Change History (16)

by anonymous, 8 years ago

Error example

comment:1 by viboes, 8 years ago

Description: modified (diff)
Owner: changed from Anthony Williams to viboes
Status: newassigned

comment:2 by viboes, 8 years ago

The error I'm seen is

test_10128.cpp: In function ‘int func(const Class1&)’:
test_10128.cpp:29:40: erreur: no matching function for call to ‘boost::unique_lock<Class1>::unique_lock(const Class1&)’
     boost::unique_lock<Class1> lock(obj);

A unique_lock<Class1> doesn't accepts a const& Class1 reference.

You wold need to use

    boost::unique_lock<const Class1> lock(obj);

And this patch

--- a/include/boost/thread/lockable_adapter.hpp
+++ b/include/boost/thread/lockable_adapter.hpp
@@ -37,11 +37,11 @@ namespace boost
     basic_lockable_adapter()
     {}
 
-    void lock()
+    void lock() const
     {
       lockable().lock();
     }
-    void unlock()
+    void unlock() const
     {
       lockable().unlock();
     }

Please, could you tell me if this work for you?

comment:3 by anonymous, 8 years ago

For me this patch is enough. It's working properly in visual C++ 2010. I suppose, it will be necesary this modification in *_lockable_adapter as timed_lockable_adapter, shared_lockable_adapter, upgrade_lockable_adapter...

Thank you very much.

comment:4 by viboes, 8 years ago

After more thoughts, I have some doubts. I'm not sure it is correct to make these lock/unlock functions const. These functions are public making the nested mutex a salient attribute.

It would be different is the mutex was not salient. E.g. synchronized_value wraps a type and makes the synchronized mutex not salient. Please, could you see if you can use synchronized_value instead?

comment:5 by viboes, 8 years ago

After yet more thoughts, lockable_adapter<const X> could be specialized so that the lock/unlcok operations do nothing (as there is no writter) and are const. What do you think?

comment:6 by anonymous, 8 years ago

For me, this last thought is better. Then, I suppose, we can use lockable_adapeter<const X>.

comment:7 by viboes, 8 years ago

There is a little problem as we can not change the inheritance of CLass1 :(

class Class1 : lockable_adapter<Class1> {...};

comment:8 by anonymous, 8 years ago

Ok. I can specialize lockable_adapter<Class1> with const members. Are you in agree with me?

comment:9 by viboes, 8 years ago

How would you write your class Class1 on the example?

comment:10 by anonymous, 8 years ago

I could derive lockable_adapter to lockable_adapter2 and use its const members.

template <typename BasicLockable>
class basic_lockable_adapter2 :
    public boost::basic_lockable_adapter<BasicLockable>
{
public:
basic_lockable_adapter2()
{}

void lock() const
{
    lockable().lock();
}
void unlock() const
{
    lockable().unlock();
}

};

class Class1 :
    public basic_lockable_adapter2<boost::recursive_mutex>
{
public:
    Class1() :_i(0){}
    virtual ~Class1(){}

    void set(int i) {
        _i = i;
    }

    int get() const {
        return _i;
    }

private:
    int _i;
};

comment:11 by viboes, 8 years ago

This doesn't corresponds to a const specialization of lockable_adapter.

BTW, I'm really thinking about the usefulness of lockable_adapter :( What about

class Class1 : boost::recursive_mutex {
...
};

?

comment:12 by anonymous, 8 years ago

Then, If I try to change class1 with this code

class Class1 :
    public boost::recursive_mutex
{
public:
    Class1() :_i(0){}
    virtual ~Class1(){}

    void set(int i) {
        _i = i;
    }

    int get() const {
        return _i;
    }

private:
    int _i;
};

int func(const Class1& obj)
{
    boost::unique_lock<const Class1> lock(obj);
    //boost::unique_lock<Class1> lock(obj);
    //boost::unique_lock<Class1> lock(const_cast<Class1&>(obj));
    return obj.get();
}


int _tmain(int argc, _TCHAR* argv[])
{
    Class1 obj;
    {
    boost::unique_lock<Class1> lock(obj);
    obj.set(1);
    }

    func(obj);

	return 0;
}

Visual C++ 2010 says me:

1>c:\desarrollo\externo\boost\boost_1_55_0\boost\thread\lock_types.hpp(331): error C2662: 'boost::detail::basic_recursive_mutex_impl<underlying_mutex_type>::unlock' : no se puede convertir el puntero 'this' de 'const Class1' a 'boost::detail::basic_recursive_mutex_impl<underlying_mutex_type> &'
1>          with
1>          [
1>              underlying_mutex_type=boost::detail::basic_timed_mutex
1>          ]
1>          Se pierden calificadores en la conversión
1>          c:\desarrollo\externo\boost\boost_1_55_0\boost\thread\lock_types.hpp(328) : durante la compilación de la función miembro de plantilla de clase 'boost::unique_lock<Mutex>::~unique_lock(void)'
1>          with
1>          [
1>              Mutex=const Class1
1>          ]
1>          c:\temp\example_lock_constobject\example_lock_constobject.cpp(50) : vea la referencia a la creación de instancias de plantilla de clase 'boost::unique_lock<Mutex>' que se está compilando
1>          with
1>          [
1>              Mutex=const Class1
1>          ]

comment:13 by viboes, 8 years ago

Off course :(

I don't see how the code in comment 10 would compile after having a specialization for const X.

comment:14 by anonymous, 8 years ago

Then, I'm afraid, I will use a member mutex in Class1 with "boost::unique_lock<boost::recursive_mutex> sl(m_mt)"

Thank you very much for your time.

comment:15 by viboes, 8 years ago

Milestone: To Be Determined
Resolution: wontfix
Status: assignedclosed
Note: See TracTickets for help on using tickets.