std::unique_lock::try_lock(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– NAME πŸ’–

std::unique_lock::try_lock β€” std::unique_lock::try_lock. Bestie, this is the C++ Standard Library manual page for std::unique_lock::try_lock(3), and it's literally all about that non-blocking lock-attempt energy. ✨

🌸 Synopsis 🌸

bool try_lock();  (since C++11)

Okay so try_lock() tries to lock β€” i.e., takes ownership of β€” the associated mutex without blocking. Effectively calls mutex()->try_lock().

std::system_error is thrown if there is no associated mutex or if the mutex is already locked by this std::unique_lock.

πŸŽ€ Parameters πŸŽ€

(none) β€” not a single parameter, bestie, we're traveling light. πŸ’…

πŸ¦‹ Return value πŸ¦‹

true if the ownership of the mutex has been acquired successfully, false otherwise. Periodt. 🫢

πŸ’€ Exceptions πŸ’€

  • Any exceptions thrown by mutex()->try_lock() (Mutex types do not throw in try_lock, but a custom Lockable might).
  • If there is no associated mutex, std::system_error with an error code of std::errc::operation_not_permitted.
  • If the mutex is already locked by this std::unique_lock, std::system_error with an error code of std::errc::resource_deadlock_would_occur.
No cap, those last two are the "you did what now?" errors. πŸ™ˆ

🧚 Example 🧚

The following examples try to acquire a mutex that was locked and unlocked. Iconic behavior, honestly. πŸ“

// Run this code

#include <chrono>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

using namespace std::chrono_literals;

int main()
{
    std::mutex counter_mutex;
    std::vector<std::thread> threads;
    using Id = int;

    auto worker_task = [&](Id id, std::chrono::seconds wait, std::chrono::seconds acquire)
    {
        // wait for a few seconds before acquiring lock.
        std::this_thread::sleep_for(wait);

        std::unique_lock<std::mutex> lock(counter_mutex, std::defer_lock);
        if (lock.try_lock())
            std::cout << '#' << id << ", lock acquired.\n";
        else
        {
            std::cout << '#' << id << ", failed acquiring lock.\n";
            return;
        }

        // keep the lock for a while.
        std::this_thread::sleep_for(acquire);

        std::cout << '#' << id << ", releasing lock (via destructor).\n";
    };

    threads.emplace_back(worker_task, Id{0}, 0s, 2s);
    threads.emplace_back(worker_task, Id{1}, 1s, 0s);
    threads.emplace_back(worker_task, Id{2}, 3s, 0s);

    for (auto& thread : threads)
        thread.join();
}

Output:

#0, lock acquired.
#1, failed acquiring lock.
#0, releasing lock (via destructor).
#2, lock acquired.
#2, releasing lock (via destructor).

πŸ‘‘ See also πŸ‘‘

  • lock β€” locks (i.e., takes ownership of) the associated mutex (public member function)
  • try_lock_for β€” attempts to lock (i.e., takes ownership of) the associated TimedLockable mutex, returns if the mutex has been unavailable for the specified time duration (public member function)
  • try_lock_until β€” tries to lock (i.e., takes ownership of) the associated TimedLockable mutex, returns if the mutex has been unavailable until specified time point has been reached (public member function)
  • unlock β€” unlocks (i.e., releases ownership of) the associated mutex (public member function)

πŸ’– Source/version: http://cppreference.com, 2024.06.10. That's the std::unique_lock::try_lock(3) manual page, bestie β€” mwah! πŸ‘‘

πŸ“¦ where this page comes from