Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TacyLockable with pthread mutexes #965

Open
CBtiger opened this issue Jan 6, 2025 · 7 comments
Open

TacyLockable with pthread mutexes #965

CBtiger opened this issue Jan 6, 2025 · 7 comments

Comments

@CBtiger
Copy link

CBtiger commented Jan 6, 2025

I am getting compile errors when tryping to use the TacyLockable() macro
with pthread mutexes in two scenarios with gcc on Linux:

  1. as class member
 class Test {
  ...
  public: 
     pthread_mutex_t       MyMutex;                            // before: ok
     TracyLockable(  pthread_mutex_t,  MyMutex );       // error
  };

Errors

MyMutex has not beed declared
expected constructor, destructor or type conversion before ';' token
  1. with "extern"
header: 
 extern pthread_mutex_t       MyMutex;    

CPP 
  pthread_mutex_t       MyMutex = PTHREAD_MUTEX_INITIALIZER;    // OK
  TracyLockable(  pthread_mutex_t,  MyMutex );                                // error, how to initialize?

Errors

conflicting declaratoion with header file line

Is there a way to deal with these two settings?

@zach2good
Copy link

In the tests you can see that TracyLockable is defining the mutex: https://github.com/wolfpld/tracy/blob/8b0b2343e1c388af5e36ff1a79bf08ef45ee1060/test/test.cpp#L103C35-L104

In your examples, you're defining the mutex and then also using TracyLockable - which redefines it.

I haven't used pthread_mutex_t, but I'd imagine you can just define:

TracyLockable(  pthread_mutex_t,  MyMutex );

and then use MyMutex as you normally would.

Here's an excerpt of code I use for locking with Tracy:

private:
    mutable TracyLockable(Mutex, mutex);

    T target;

    auto lock() const
    {
        return ReadLock<LockableBase(Mutex)>(mutex);
    }

@CBtiger
Copy link
Author

CBtiger commented Jan 7, 2025

I tried the same with the std::mutex equivalents. I can not see why the extern declaration worked without the macro and it does not work with it.

But the more important use case is to use track a mutex which is a class member. There I can not see another way to define it. Do you think your system should work with that?

@zach2good
Copy link

zach2good commented Jan 7, 2025

Here is the full version of the code I use for this guarding; which pairs a type T with a mutex and provides access, while working nicely with Tracy:

// https://www.reddit.com/r/cpp/comments/p132c7/comment/h8b8nml/?share_id=-NRyj9iRw5TqSi4Mm381j
template <
    class T,
    class M                            = std::mutex,
    template <typename...> typename WL = std::unique_lock,
    template <typename...> typename RL = std::unique_lock>
struct mutex_guarded
{
    mutex_guarded()  = default;
    ~mutex_guarded() = default;

    explicit mutex_guarded(T in)
    : target(std::move(in))
    {
    }

    auto read(auto f) const
    {
        auto l = lock();
        LockMark(mutex);
        return f(target);
    }

    auto write(auto f)
    {
        auto l = lock();
        LockMark(mutex);
        return f(target);
    }

private:
    mutable TracyLockable(M, mutex);

    T target;

    auto lock() const
    {
        return RL<LockableBase(M)>(mutex);
    }

    auto lock()
    {
        return WL<LockableBase(M)>(mutex);
    }
};
mutex_guarded<std::unordered_map<std::string, time_point>> lastExecutionTimes_;

lastExecutionTimes_.write([&](auto& lastExecutionTimes) { ... }));

@CBtiger
Copy link
Author

CBtiger commented Jan 7, 2025

@zach2good
Thanks for your code.

Edit: I was able to compile it using "-fpermissive". I had forgotten to add tracy path and lib.

I wonder why you used templates. Because its more convenient to use or because there is no other way to get it to work (i.e. w/o templates)?

@zach2good
Copy link

I did it this way to easily mark mutex_guarded resources in my codebase, and then users are forced to either read(...) or write(...) from the guarded object.

You could easily embed mutable TracyLockable(std::mutex, mutex); and lock with std::lock_guard<LockableBase(std::mutex)> lock(mutex); without any templates, if you wanted to.

@zach2good
Copy link

This also means that I only have one area in my code where I deal with mutexes, and anywhere I use this template is correctly reported to Tracy

@CBtiger
Copy link
Author

CBtiger commented Jan 7, 2025

Right. OK I get the idea with the template.

I am trying to get it to work with pthread which is not using templates. Thats why after the definition with Tracy you can not

use "MyMutex" as you normally would.

For example, the call to lock the mutex would require a pointer to the mutex

pthread_mutex_lock( &MyMutex );

but tracy seems to assign the variable to the type tracy::Lockable<pthread_mutex_t> and the compiler complains error "can't convert tracy::Lockable<pthread_mutex_t>* to pthread_mutex_t*" .

I did not yet find out how to get to the original pointer or how to call the lock function in a tracy conformal way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants