• fun with a mutex...

    From Chris M. Thomasson@3:633/280.2 to All on Wed Jul 30 15:54:21 2025
    This is using the idea of trying to do other work while a mutex is
    contended. Why spin or wait when we don't really have to? The per-thread random numbers in this experiment are only there to try to simulate when
    a contended thread has any other work to do. This can be check
    per-thread stacks, queues, ect... Here is my example code. Can you get
    it to run, and can you show me the output? Now, this can work in real
    world environments. It's a stare to an adaptive mutex that just spins
    doing nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    ____________________________________
    // A Fun Mutex Pattern? Or, a Nightmare? Humm...
    // By: Chris M. Thomasson
    //___________________________________________________


    #include <iostream>
    #include <random>
    #include <numeric>
    #include <algorithm>
    #include <thread>
    #include <atomic>
    #include <mutex>


    #define CT_WORKERS (42)
    #define CT_ITERS (996699)
    #define CT_BACKOFFS (42)
    #define CT_RAND_MAX (20)
    #define CT_RAND_THRESHOLD (5)


    struct ct_shared
    {
    std::mutex m_fun_mutex;
    std::atomic<unsigned long> m_other_work = { 0 };
    int m_test_count0 = 0;

    void
    sanity_check_dump() const
    {
    std::cout << "(ct_shared:" << this << ")->" <<
    "m_test_count0 = " << m_test_count0 << ", " <<
    "m_other_work = " << m_other_work.load(std::memory_order_relaxed) << "\n";
    }

    bool
    sanity_check_validate() const
    {
    return (m_test_count0 == CT_ITERS * CT_WORKERS);
    }
    };



    void
    ct_worker_entry(
    ct_shared& shared
    ) {
    //std::cout << "ct_worker_entry" << std::endl; // testing thread
    race for sure...

    // Thread Local...
    std::random_device rnd_seed = { };
    std::mt19937 rnd_gen(rnd_seed());
    std::uniform_int_distribution<unsigned long> rnd_dist(0, CT_RAND_MAX);

    for (unsigned long i = 0; i < CT_ITERS; ++i)
    {
    // Lock logic...
    {
    unsigned long backoff = 0;

    while (! shared.m_fun_mutex.try_lock())
    {
    unsigned long rnd0 = rnd_dist(rnd_gen);

    if (rnd0 > CT_RAND_THRESHOLD || backoff > CT_BACKOFFS)
    {
    shared.m_fun_mutex.lock();
    break;
    }

    // do other work... :^)
    shared.m_other_work.fetch_add(1,
    std::memory_order_relaxed);

    // but not too much work... ;^o
    ++backoff;
    }
    }

    // Critical Section...
    {
    shared.m_test_count0 = shared.m_test_count0 + 1;
    }

    // Unlock
    {
    shared.m_fun_mutex.unlock();
    }
    }
    }


    int main()
    {
    // Hello... :^)
    {
    std::cout << "Hello ct_fun_mutex... lol? ;^) ver:(0.0.0)\n";
    std::cout << "By: Chris M. Thomasson\n";
    std::cout << "____________________________________________________\n";
    std::cout.flush();
    }

    // Create our fun things... ;^)
    ct_shared shared = { };
    std::thread workers[CT_WORKERS] = { };

    // Lanuch...
    {
    std::cout << "Launching Threads...\n";
    std::cout.flush();

    for (unsigned long i = 0; i < CT_WORKERS; ++i)
    {
    workers[i] = std::thread(ct_worker_entry, std::ref(shared));
    }
    }

    // Join...
    {
    std::cout << "Joining Threads... (computing :^)\n";
    std::cout.flush();
    for (unsigned long i = 0; i < CT_WORKERS; ++i)
    {
    workers[i].join();
    }
    }

    // Sanity Check...
    {
    shared.sanity_check_dump();

    if (! shared.sanity_check_validate())
    {
    std::cout << "\n\n**** Pardon my French, but FUCK!!!!!
    ****\n" << std::endl;
    }

    else
    {
    std::cout << "\nWe are Sane!\n\n";
    std::cout << "We completed " <<
    shared.m_other_work.load(std::memory_order_relaxed) <<
    " work items while waiting for the mutex..." << std::endl;
    }
    }

    // Fin...
    {
    std::cout << "____________________________________________________\n";
    std::cout << "Fin... :^)\n" << std::endl;
    }

    return 0;
    }
    ____________________________________

    Any luck? Its fun to see how many work items were completed when the
    mutex was contended...

    --- MBSE BBS v1.1.1 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sun Aug 3 05:58:23 2025
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is contended. Why spin or wait when we don't really have to? The per-thread random numbers in this experiment are only there to try to simulate when
    a contended thread has any other work to do. This can be check per-
    thread stacks, queues, ect... Here is my example code. Can you get it to run, and can you show me the output? Now, this can work in real world environments. It's a stare to an adaptive mutex that just spins doing nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the
    mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can _try_
    to do "other" work... That can be checking thread local queues, stacks,
    even try to get an io completion (think GetQueuedCompletionStatus() with
    a timeout of 0), if there is no other work to do, then we fallback to a lock(). If we are doing other work, we have to limit it via CT_BACKOFFS,
    then fall back to lock(). So, it allows for a so-called "productive
    backoff", instead of a run of the mill adaptive mutex that spins in
    userspace doing nothing before it goes to the kernel to wait on a
    contended mutex. Sound okay?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sun Aug 3 06:00:00 2025
    On 8/2/2025 12:58 PM, Chris M. Thomasson wrote:
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is
    contended. Why spin or wait when we don't really have to? The per-
    thread random numbers in this experiment are only there to try to
    simulate when a contended thread has any other work to do. This can be
    check per- thread stacks, queues, ect... Here is my example code. Can
    you get it to run, and can you show me the output? Now, this can work
    in real world environments. It's a stare to an adaptive mutex that
    just spins doing nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the
    mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can _try_
    to do "other" work... That can be checking thread local queues, stacks,
    even try to get an io completion (think GetQueuedCompletionStatus() with
    ^^^^^^^^^^^^^^^^^^^^^^
    Oh shit. That should be GetQueuedCompletionStatusEx(), its much better.

    https://learn.microsoft.com/en-us/windows/win32/fileio/getqueuedcompletionstatusex-func

    a timeout of 0), if there is no other work to do, then we fallback to a lock(). If we are doing other work, we have to limit it via CT_BACKOFFS, then fall back to lock(). So, it allows for a so-called "productive backoff", instead of a run of the mill adaptive mutex that spins in userspace doing nothing before it goes to the kernel to wait on a
    contended mutex. Sound okay?


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Mon Aug 4 18:48:33 2025
    On Sat, 2 Aug 2025 12:58:23 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is
    contended. Why spin or wait when we don't really have to? The per-thread
    random numbers in this experiment are only there to try to simulate when
    a contended thread has any other work to do. This can be check per-
    thread stacks, queues, ect... Here is my example code. Can you get it to
    run, and can you show me the output? Now, this can work in real world
    environments. It's a stare to an adaptive mutex that just spins doing
    nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the
    mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can _try_
    to do "other" work... That can be checking thread local queues, stacks,

    I never really understood the point of this semi-sequential paradigm. If you have other work to do then do it in another thread, thats the whole point of threading! Meanwhile if a thread needs to wait for a lock then just let it wait.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 5 05:34:08 2025
    On 8/4/2025 1:48 AM, Muttley@DastardlyHQ.org wrote:
    On Sat, 2 Aug 2025 12:58:23 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is
    contended. Why spin or wait when we don't really have to? The per-thread >>> random numbers in this experiment are only there to try to simulate when >>> a contended thread has any other work to do. This can be check per-
    thread stacks, queues, ect... Here is my example code. Can you get it to >>> run, and can you show me the output? Now, this can work in real world
    environments. It's a stare to an adaptive mutex that just spins doing
    nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the
    mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can _try_
    to do "other" work... That can be checking thread local queues, stacks,

    I never really understood the point of this semi-sequential paradigm. If you have other work to do then do it in another thread, thats the whole point of threading!

    This already works with multiple threads, no problem. But, if a thread
    fails to acquire the mutex, it can check to see if it has any other work
    to do instead of just waiting in the kernel doing nothing, or spinning
    doing nothing... Make sense to you?


    Meanwhile if a thread needs to wait for a lock then just let it wait.


    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin for a bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real
    work? It will keep the thread hot, doing work instead of just waiting...



    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 5 05:38:52 2025
    On 8/4/2025 1:48 AM, Muttley@DastardlyHQ.org wrote:
    On Sat, 2 Aug 2025 12:58:23 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is
    contended. Why spin or wait when we don't really have to? The per-thread >>> random numbers in this experiment are only there to try to simulate when >>> a contended thread has any other work to do. This can be check per-
    thread stacks, queues, ect... Here is my example code. Can you get it to >>> run, and can you show me the output? Now, this can work in real world
    environments. It's a stare to an adaptive mutex that just spins doing
    nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the
    mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can _try_
    to do "other" work... That can be checking thread local queues, stacks,

    I never really understood the point of this semi-sequential paradigm. If you have other work to do then do it in another thread, thats the whole point of threading! Meanwhile if a thread needs to wait for a lock then just let it wait.


    Lol. I asked an AI about it. Well, it seemed to "like" it and spit out
    some code:

    AI generated:
    __________________________________
    #include <iostream>
    #include <random>
    #include <thread>
    #include <atomic>
    #include <mutex>
    #include <queue>
    #include <chrono>

    #define CT_WORKERS (103)
    #define CT_ITERS (6996699)
    #define CT_BACKOFFS (42)
    #define CT_RAND_MAX (1000 )
    #define CT_RAND_THRESHOLD (969)

    struct io_packet {
    int id;
    char payload[64];
    };

    thread_local std::queue<io_packet> local_io_queue;

    io_packet generate_io_packet(int id) {
    io_packet pkt;
    pkt.id = id;
    for (int i = 0; i < 64; i++) {
    pkt.payload[i] = (char)((id + i) % 256);
    }
    return pkt;
    }

    struct ct_shared {
    std::mutex m_fun_mutex;
    std::atomic<unsigned long> m_other_work{ 0 };
    std::atomic<unsigned long> m_io_work{ 0 };
    int m_test_count0 = 0;
    bool sanity_check_validate() const {
    return (m_test_count0 == CT_ITERS * CT_WORKERS);
    }
    };

    void do_other_work(ct_shared & shared) {
    for (volatile int k = 0; k < 50; ++k) {}
    shared.m_other_work.fetch_add(1, std::memory_order_relaxed);

    if (!local_io_queue.empty()) {
    local_io_queue.pop();
    shared.m_io_work.fetch_add(1, std::memory_order_relaxed);
    }
    else {
    local_io_queue.push(generate_io_packet(rand()));
    }
    }

    void worker_productive(ct_shared & shared) {
    std::random_device rnd_seed;
    std::mt19937 rnd_gen(rnd_seed());
    std::uniform_int_distribution<unsigned long> rnd_dist(0, CT_RAND_MAX);

    for (unsigned long i = 0; i < CT_ITERS; ++i) {
    unsigned long backoff = 0;
    while (!shared.m_fun_mutex.try_lock()) {
    unsigned long rnd0 = rnd_dist(rnd_gen);
    if (rnd0 > CT_RAND_THRESHOLD || backoff > CT_BACKOFFS) {
    shared.m_fun_mutex.lock();
    break;
    }
    do_other_work(shared);
    ++backoff;
    }
    shared.m_test_count0 += 1;
    shared.m_fun_mutex.unlock();
    }
    }

    void worker_baseline(ct_shared & shared) {
    for (unsigned long i = 0; i < CT_ITERS; ++i) {
    shared.m_fun_mutex.lock();
    shared.m_test_count0 += 1;
    shared.m_fun_mutex.unlock();
    }
    }

    int main() {
    using clock = std::chrono::high_resolution_clock;

    ct_shared shared_prod;
    auto start_prod = clock::now();
    {
    std::thread workers[CT_WORKERS];
    for (int i = 0; i < CT_WORKERS; i++)
    workers[i] = std::thread(worker_productive, std::ref(shared_prod));
    for (int i = 0; i < CT_WORKERS; i++)
    workers[i].join();
    }
    auto end_prod = clock::now();

    if (!shared_prod.sanity_check_validate()) {
    std::cout << "Error: sanity check failed for productive version\n";
    return 1;
    }

    auto prod_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_prod - start_prod).count();
    std::cout << "Productive mutex:\n";
    std::cout << " Elapsed time: " << prod_time_ms << " ms\n";
    std::cout << " CPU-bound other work: " << shared_prod.m_other_work.load() << "\n";
    std::cout << " IO completions processed: " << shared_prod.m_io_work.load() << "\n";
    std::cout << " Total useful work (main + other + IO): "
    << (shared_prod.m_other_work.load() +
    shared_prod.m_io_work.load() + (CT_WORKERS * CT_ITERS)) << "\n\n";

    ct_shared shared_base;
    auto start_base = clock::now();
    {
    std::thread workers[CT_WORKERS];
    for (int i = 0; i < CT_WORKERS; i++)
    workers[i] = std::thread(worker_baseline,
    std::ref(shared_base));
    for (int i = 0; i < CT_WORKERS; i++)
    workers[i].join();
    }
    auto end_base = clock::now();

    if (!shared_base.sanity_check_validate()) {
    std::cout << "Error: sanity check failed for baseline version\n";
    return 1;
    }

    auto base_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_base - start_base).count();
    std::cout << "Baseline mutex:\n";
    std::cout << " Elapsed time: " << base_time_ms << " ms\n";
    std::cout << " CPU-bound other work: " << shared_base.m_other_work.load() << "\n";
    std::cout << " IO completions processed: " << shared_base.m_io_work.load() << "\n";
    std::cout << " Total useful work (main + other + IO): "
    << (shared_base.m_other_work.load() +
    shared_base.m_io_work.load() + (CT_WORKERS * CT_ITERS)) << "\n\n";

    double throughput_gain = 100.0 *
    ((shared_prod.m_other_work.load() +
    shared_prod.m_io_work.load() + (CT_WORKERS * CT_ITERS))
    - (shared_base.m_other_work.load() +
    shared_base.m_io_work.load() + (CT_WORKERS * CT_ITERS)))
    / (double)(CT_WORKERS * CT_ITERS);
    std::cout << "Total useful throughput gain vs baseline: " << throughput_gain << "%\n";

    return 0;
    }
    __________________________________

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Aug 5 17:27:17 2025
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 8/4/2025 1:48 AM, Muttley@DastardlyHQ.org wrote:
    I never really understood the point of this semi-sequential paradigm. If you >> have other work to do then do it in another thread, thats the whole point of >> threading!

    This already works with multiple threads, no problem. But, if a thread
    fails to acquire the mutex, it can check to see if it has any other work
    to do instead of just waiting in the kernel doing nothing, or spinning
    doing nothing... Make sense to you?

    Yes, I understand the concept, its not rocket science.

    Meanwhile if a thread needs to wait for a lock then just let it wait.


    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin for a >bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real
    work? It will keep the thread hot, doing work instead of just waiting...

    Because while its doing something else the lock maybe become free then
    become acquired again leading to a kind of race condition of some threads constantly bouncing off locks, checking for other work (which takes cpu
    cycles) , finding nothing then going back to the lock, rinse and repeat.
    Far simpler to have thread waiting on locks while other threads get on with work. Its not only more efficient it also leads to simpler code.



    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Muttley@DastardlyHQ.org@3:633/280.2 to All on Tue Aug 5 17:29:18 2025
    On Mon, 4 Aug 2025 12:38:52 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    Lol. I asked an AI about it. Well, it seemed to "like" it and spit out
    some code:

    AI generated:

    I'm not even going to attempt to figure out wtf is going on there. Looks
    like it ripped off code from some project on github wholesale.



    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Fred. Zwarts@3:633/280.2 to All on Tue Aug 5 18:27:21 2025
    Op 04.aug.2025 om 21:34 schreef Chris M. Thomasson:
    On 8/4/2025 1:48 AM, Muttley@DastardlyHQ.org wrote:
    On Sat, 2 Aug 2025 12:58:23 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is
    contended. Why spin or wait when we don't really have to? The per-
    thread
    random numbers in this experiment are only there to try to simulate
    when
    a contended thread has any other work to do. This can be check per-
    thread stacks, queues, ect... Here is my example code. Can you get
    it to
    run, and can you show me the output? Now, this can work in real world
    environments. It's a stare to an adaptive mutex that just spins doing
    nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the
    mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can _try_
    to do "other" work... That can be checking thread local queues, stacks,

    I never really understood the point of this semi-sequential paradigm.
    If you
    have other work to do then do it in another thread, thats the whole
    point of
    threading!

    This already works with multiple threads, no problem. But, if a thread
    fails to acquire the mutex, it can check to see if it has any other work
    to do instead of just waiting in the kernel doing nothing, or spinning
    doing nothing... Make sense to you?


    Meanwhile if a thread needs to wait for a lock then just let it wait.


    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin for a bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real
    work? It will keep the thread hot, doing work instead of just waiting...


    Maybe in old single processor systems it could be useful to avoid
    spinning and make the processor available for other work.
    Nowadays each system has many processors and if one of them spins for a
    brief period, that is not a problem. The work that can be done when one
    thread is spinning, can be done in other threads.
    So, the need for such a complicated solution might be present only in
    very exceptional cases.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Wed Aug 6 09:07:45 2025
    On 8/5/2025 1:27 AM, Fred. Zwarts wrote:
    Op 04.aug.2025 om 21:34 schreef Chris M. Thomasson:
    On 8/4/2025 1:48 AM, Muttley@DastardlyHQ.org wrote:
    On Sat, 2 Aug 2025 12:58:23 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is
    contended. Why spin or wait when we don't really have to? The per-
    thread
    random numbers in this experiment are only there to try to simulate >>>>> when
    a contended thread has any other work to do. This can be check per-
    thread stacks, queues, ect... Here is my example code. Can you get
    it to
    run, and can you show me the output? Now, this can work in real world >>>>> environments. It's a stare to an adaptive mutex that just spins doing >>>>> nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the >>>>> mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can _try_ >>>> to do "other" work... That can be checking thread local queues, stacks, >>>
    I never really understood the point of this semi-sequential paradigm.
    If you
    have other work to do then do it in another thread, thats the whole
    point of
    threading!

    This already works with multiple threads, no problem. But, if a thread
    fails to acquire the mutex, it can check to see if it has any other
    work to do instead of just waiting in the kernel doing nothing, or
    spinning doing nothing... Make sense to you?


    Meanwhile if a thread needs to wait for a lock then just let it wait.


    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin for
    a bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real
    work? It will keep the thread hot, doing work instead of just waiting...


    Maybe in old single processor systems it could be useful to avoid
    spinning and make the processor available for other work.
    Nowadays each system has many processors and if one of them spins for a brief period, that is not a problem. The work that can be done when one thread is spinning, can be done in other threads.
    So, the need for such a complicated solution might be present only in
    very exceptional cases.

    Say the mutex is not all that "critical" to grab. Also, the backoff
    limit is there to make sure that the mutex shall be acquired. Also, a
    lot of this other work can be thread local, so another thread cannot
    start working on it? When the mutex is acquired a thread can do some interesting things. Check global state, check for update commands, to
    update the server, ect... But, the point is that when the mutex is not
    able to be locked, the thread will at least try to do something else? Is
    this okay, or just pie in the sky crap?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Wed Aug 6 09:08:58 2025
    On 8/5/2025 12:29 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:38:52 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    Lol. I asked an AI about it. Well, it seemed to "like" it and spit out
    some code:

    AI generated:

    I'm not even going to attempt to figure out wtf is going on there. Looks
    like it ripped off code from some project on github wholesale.



    Afaict, it seems to be trying to show how much other work can be done
    when a try_lock fails, vs just waiting on the mutex spinning and/or
    waiting in the kernel?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Wed Aug 6 09:10:34 2025
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 8/4/2025 1:48 AM, Muttley@DastardlyHQ.org wrote:
    I never really understood the point of this semi-sequential paradigm. If you
    have other work to do then do it in another thread, thats the whole point of
    threading!

    This already works with multiple threads, no problem. But, if a thread
    fails to acquire the mutex, it can check to see if it has any other work
    to do instead of just waiting in the kernel doing nothing, or spinning
    doing nothing... Make sense to you?

    Yes, I understand the concept, its not rocket science.

    Meanwhile if a thread needs to wait for a lock then just let it wait.


    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin for a
    bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real
    work? It will keep the thread hot, doing work instead of just waiting...

    Because while its doing something else the lock maybe become free then
    become acquired again leading to a kind of race condition of some threads

    Nope. A thread can only do something else for a bounded number of times.
    So, its starvation free. No race condition.


    constantly bouncing off locks, checking for other work (which takes cpu cycles) , finding nothing then going back to the lock, rinse and repeat.
    Far simpler to have thread waiting on locks while other threads get on with work. Its not only more efficient it also leads to simpler code.




    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Wed Aug 6 10:38:54 2025
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread
    fails to acquire the mutex, it can check to see if it has any other work >>> to do instead of just waiting in the kernel doing nothing, or spinning
    doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin for a >>> bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real
    work? It will keep the thread hot, doing work instead of just waiting...

    Because while its doing something else the lock maybe become free then
    become acquired again leading to a kind of race condition of some threads

    Nope. A thread can only do something else for a bounded number of times.
    So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is
    computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call). What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Wed Aug 6 12:14:21 2025
    On 8/5/2025 5:38 PM, Dan Cross wrote:
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread >>>> fails to acquire the mutex, it can check to see if it has any other work >>>> to do instead of just waiting in the kernel doing nothing, or spinning >>>> doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin for a >>>> bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real >>>> work? It will keep the thread hot, doing work instead of just waiting... >>>
    Because while its doing something else the lock maybe become free then
    become acquired again leading to a kind of race condition of some threads >>
    Nope. A thread can only do something else for a bounded number of times.
    So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call).

    This is where try to do other work, well. Also, this is where the
    nightmare condition can occur. Try to do other work, non-blocking. Say
    trying to take a IOCP completion using a timeout of zero? If we got
    data, we add it to a local queue or something. No blocking.



    What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    No. If there is no other work to do, it falls back to lock(). If if did
    too much work, it falls back to lock.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Wed Aug 6 12:16:41 2025
    On 8/5/2025 5:38 PM, Dan Cross wrote:
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread >>>> fails to acquire the mutex, it can check to see if it has any other work >>>> to do instead of just waiting in the kernel doing nothing, or spinning >>>> doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin for a >>>> bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real >>>> work? It will keep the thread hot, doing work instead of just waiting... >>>
    Because while its doing something else the lock maybe become free then
    become acquired again leading to a kind of race condition of some threads >>
    Nope. A thread can only do something else for a bounded number of times.
    So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call). What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    - Dan C.


    Using this pattern, well, can be a nightmare, but can be somewhat
    beneficial at the same time? If a programmer knew that a class of
    functions are compatible with the try_lock failed condition, well, why
    not give them a go? Better than spinning doing nothing, or god forbid,
    waiting in the kernel?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Fred. Zwarts@3:633/280.2 to All on Wed Aug 6 18:56:59 2025
    Op 06.aug.2025 om 01:07 schreef Chris M. Thomasson:
    On 8/5/2025 1:27 AM, Fred. Zwarts wrote:
    Op 04.aug.2025 om 21:34 schreef Chris M. Thomasson:
    On 8/4/2025 1:48 AM, Muttley@DastardlyHQ.org wrote:
    On Sat, 2 Aug 2025 12:58:23 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is >>>>>> contended. Why spin or wait when we don't really have to? The per- >>>>>> thread
    random numbers in this experiment are only there to try to
    simulate when
    a contended thread has any other work to do. This can be check per- >>>>>> thread stacks, queues, ect... Here is my example code. Can you get >>>>>> it to
    run, and can you show me the output? Now, this can work in real world >>>>>> environments. It's a stare to an adaptive mutex that just spins doing >>>>>> nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the >>>>>> mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can
    _try_
    to do "other" work... That can be checking thread local queues,
    stacks,

    I never really understood the point of this semi-sequential
    paradigm. If you
    have other work to do then do it in another thread, thats the whole
    point of
    threading!

    This already works with multiple threads, no problem. But, if a
    thread fails to acquire the mutex, it can check to see if it has any
    other work to do instead of just waiting in the kernel doing nothing,
    or spinning doing nothing... Make sense to you?


    Meanwhile if a thread needs to wait for a lock then just let it wait.


    The idea is instead of letting it wait, why not let it try to do some
    other work? Think of an adaptive mutex. On contention it will spin
    for a bounded number of times in user space before having to wait in
    the kernel. Well, instead of spinning, try to do something else, some
    real work? It will keep the thread hot, doing work instead of just
    waiting...


    Maybe in old single processor systems it could be useful to avoid
    spinning and make the processor available for other work.
    Nowadays each system has many processors and if one of them spins for
    a brief period, that is not a problem. The work that can be done when
    one thread is spinning, can be done in other threads.
    So, the need for such a complicated solution might be present only in
    very exceptional cases.

    Say the mutex is not all that "critical" to grab. Also, the backoff
    limit is there to make sure that the mutex shall be acquired. Also, a
    lot of this other work can be thread local, so another thread cannot
    start working on it? When the mutex is acquired a thread can do some interesting things. Check global state, check for update commands, to
    update the server, ect... But, the point is that when the mutex is not
    able to be locked, the thread will at least try to do something else? Is this okay, or just pie in the sky crap?


    As I said, i can see some very exceptional cases where this may be needed.
    But in the general case it is too vague, because 'something else' is not
    well defined. In the general case I would prefer a redesign, where the 'something else' is done in another thread.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Wed Aug 6 21:29:37 2025
    In article <106udpt$3400b$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 5:38 PM, Dan Cross wrote:
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread >>>>> fails to acquire the mutex, it can check to see if it has any other work >>>>> to do instead of just waiting in the kernel doing nothing, or spinning >>>>> doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some >>>>> other work? Think of an adaptive mutex. On contention it will spin for a >>>>> bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real >>>>> work? It will keep the thread hot, doing work instead of just waiting... >>>>
    Because while its doing something else the lock maybe become free then >>>> become acquired again leading to a kind of race condition of some threads >>>
    Nope. A thread can only do something else for a bounded number of times. >>> So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is
    computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call).

    This is where try to do other work, well. Also, this is where the
    nightmare condition can occur. Try to do other work, non-blocking.

    If you are talking about some kind of general mechanism, how
    would you even know in advance what the "something else" is?

    Say
    trying to take a IOCP completion using a timeout of zero? If we got
    data, we add it to a local queue or something. No blocking.

    You're talking about Win32, consider how
    `GetQueuedCompletionStatus` might be implemented. You may well
    be taking a round-trip through the kernel to do that, which is
    very expensive compared to, say, incrementing a register.

    What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    No. If there is no other work to do, it falls back to lock(). If if did
    too much work, it falls back to lock.

    You're missing the point: there's no good way to determine
    whether _any_ amount of work is "too much".

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Wed Aug 6 22:04:49 2025
    In article <106udu9$3400b$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 5:38 PM, Dan Cross wrote:
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread >>>>> fails to acquire the mutex, it can check to see if it has any other work >>>>> to do instead of just waiting in the kernel doing nothing, or spinning >>>>> doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some >>>>> other work? Think of an adaptive mutex. On contention it will spin for a >>>>> bounded number of times in user space before having to wait in the
    kernel. Well, instead of spinning, try to do something else, some real >>>>> work? It will keep the thread hot, doing work instead of just waiting... >>>>
    Because while its doing something else the lock maybe become free then >>>> become acquired again leading to a kind of race condition of some threads >>>
    Nope. A thread can only do something else for a bounded number of times. >>> So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is
    computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call). What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    Using this pattern, well, can be a nightmare, but can be somewhat
    beneficial at the same time?

    Yeah, so beneficial that it's been codified many times over:
    acquiring a contended blocking mutex yields, so that something
    else can run instead.

    If a programmer knew that a class of
    functions are compatible with the try_lock failed condition, well, why
    not give them a go? Better than spinning doing nothing, or god forbid, >waiting in the kernel?

    The whole premise of a spinlock is that the critical section
    that it protects is short (like, a few instructions), so the
    overhead of spinning is smaller than the overhead of context
    switching to something else. If that is not true, you shouldn't
    be using a spinlock as your mutex primitive in the first place,
    and a blocking or adaptive mutex is more appropriate. By the
    way, there's nothing at all wrong with blocking in the kernel;
    given a reasonable OS, it's not like if *YOUR THREAD* isn't
    running the CPU will be idle or something.

    But if you still want to avoid blocking when a mutex is
    unavailable, then you've got the idea inverted. Focusing on the
    locking protocol as some kind of generic place to do "other
    work" is too general to be useful, as has been shown. To be
    truly useful, this sort of approach must be coupled with
    knowledge of what a thread can safely do in context, which means
    that you really need to specialize the behavior for the
    _critical section_, not the _mutex_: the programmer knows why
    the thread is trying to acquire a mutex in that case, and what
    other work may or may not be acceptable to do if the mutex isn't
    immediately available. So they can craft the critical section
    to take advantage of that knowledge themselves. This sort of
    technique is well-known, by the way.

    But then it's not going to be particularly general. And you may
    argue that the critical section might be buried deep down in a
    call stack, very far away from the place where the programmer
    can reasonably make a decision about whether it's safe to do
    something or not, so that's a more appropriate place: but that
    reinforces the objections: if the critical section is so far
    away from the point where the programmer knows whether it's safe
    for the thread to do something else, then the programmer doesn't
    really know whether that thing is safe, because the intervening
    calls might have changed conditions so that it's not, so trying
    to plumb that knowledge down to the mutex code is again too
    dangerous to be useful.

    But even if the programmer could safely interpose doing
    "something else" in this way, they may not have full knowledge
    to know whether or not that will cause the thread to block.
    Consider, for example, a program that tries to do something
    innocuous, like zero a a few byte's worth of memory while
    trying to take a lock; what if the page holding the memory to be
    zero'ed has been stolen by the OS in the meantime, and now the
    program (totally unbeknownst to it) incurs a page fault that
    requires reading data from secondary storage to resolve? Not
    only has a single store now blocked your thread in the big scary
    kernel, but it's blocked it for many, many cycles.

    So while this technique is known and used in existing systems,
    it must be done so carefully that it really isn't appropriate as
    a general mechanism.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Wed Aug 6 23:51:50 2025
    Am 30.07.2025 um 07:54 schrieb Chris M. Thomasson:

    This is using the idea of trying to do other work while a mutex is contended. ...

    This situation almost never happens.
    It requires that the locking can be delayed an arbitrary time.
    You feel like a genius with that and you've invented nonsense.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Thu Aug 7 08:34:49 2025
    On 8/6/2025 6:51 AM, Bonita Montero wrote:
    Am 30.07.2025 um 07:54 schrieb Chris M. Thomasson:

    This is using the idea of trying to do other work while a mutex is
    contended. ...

    This situation almost never happens.
    It requires that the locking can be delayed an arbitrary time.

    Not an arbitrary time. Its bounded.


    You feel like a genius with that and you've invented nonsense.


    Huh? Don't project on me. I was asking a question.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Thu Aug 7 08:36:58 2025
    On 8/6/2025 1:56 AM, Fred. Zwarts wrote:
    Op 06.aug.2025 om 01:07 schreef Chris M. Thomasson:
    On 8/5/2025 1:27 AM, Fred. Zwarts wrote:
    Op 04.aug.2025 om 21:34 schreef Chris M. Thomasson:
    On 8/4/2025 1:48 AM, Muttley@DastardlyHQ.org wrote:
    On Sat, 2 Aug 2025 12:58:23 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    On 7/29/2025 10:54 PM, Chris M. Thomasson wrote:
    This is using the idea of trying to do other work while a mutex is >>>>>>> contended. Why spin or wait when we don't really have to? The
    per- thread
    random numbers in this experiment are only there to try to
    simulate when
    a contended thread has any other work to do. This can be check per- >>>>>>> thread stacks, queues, ect... Here is my example code. Can you
    get it to
    run, and can you show me the output? Now, this can work in real >>>>>>> world
    environments. It's a stare to an adaptive mutex that just spins >>>>>>> doing
    nothing... lol... ;^)

    I compiled it using c++20

    (read all...)
    [snip code]
    Any luck? Its fun to see how many work items were completed when the >>>>>>> mutex was contended...

    I guess the main point is that if a try_lock() fails, then we can >>>>>> _try_
    to do "other" work... That can be checking thread local queues,
    stacks,

    I never really understood the point of this semi-sequential
    paradigm. If you
    have other work to do then do it in another thread, thats the whole >>>>> point of
    threading!

    This already works with multiple threads, no problem. But, if a
    thread fails to acquire the mutex, it can check to see if it has any
    other work to do instead of just waiting in the kernel doing
    nothing, or spinning doing nothing... Make sense to you?


    Meanwhile if a thread needs to wait for a lock then just let it wait. >>>>>

    The idea is instead of letting it wait, why not let it try to do
    some other work? Think of an adaptive mutex. On contention it will
    spin for a bounded number of times in user space before having to
    wait in the kernel. Well, instead of spinning, try to do something
    else, some real work? It will keep the thread hot, doing work
    instead of just waiting...


    Maybe in old single processor systems it could be useful to avoid
    spinning and make the processor available for other work.
    Nowadays each system has many processors and if one of them spins for
    a brief period, that is not a problem. The work that can be done when
    one thread is spinning, can be done in other threads.
    So, the need for such a complicated solution might be present only in
    very exceptional cases.

    Say the mutex is not all that "critical" to grab. Also, the backoff
    limit is there to make sure that the mutex shall be acquired. Also, a
    lot of this other work can be thread local, so another thread cannot
    start working on it? When the mutex is acquired a thread can do some
    interesting things. Check global state, check for update commands, to
    update the server, ect... But, the point is that when the mutex is not
    able to be locked, the thread will at least try to do something else?
    Is this okay, or just pie in the sky crap?


    As I said, i can see some very exceptional cases where this may be needed. But in the general case it is too vague, because 'something else' is not well defined. In the general case I would prefer a redesign, where the 'something else' is done in another thread.

    Fair enough. But, well, if "something else" can be done in the same
    thread, well, why not try it, if the mutex is locked in the mean time? Grasping at straws here? Humm... It's a very specialized back off. I
    think it can be more "productive" than your run of the mill adaptive
    mutex, in a sense. Instead of spin, try something else...

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Thu Aug 7 08:43:13 2025
    On 8/6/2025 4:29 AM, Dan Cross wrote:
    In article <106udpt$3400b$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 5:38 PM, Dan Cross wrote:
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread >>>>>> fails to acquire the mutex, it can check to see if it has any other work >>>>>> to do instead of just waiting in the kernel doing nothing, or spinning >>>>>> doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some >>>>>> other work? Think of an adaptive mutex. On contention it will spin for a >>>>>> bounded number of times in user space before having to wait in the >>>>>> kernel. Well, instead of spinning, try to do something else, some real >>>>>> work? It will keep the thread hot, doing work instead of just waiting... >>>>>
    Because while its doing something else the lock maybe become free then >>>>> become acquired again leading to a kind of race condition of some threads >>>>
    Nope. A thread can only do something else for a bounded number of times. >>>> So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is
    computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call).

    This is where try to do other work, well. Also, this is where the
    nightmare condition can occur. Try to do other work, non-blocking.

    If you are talking about some kind of general mechanism, how
    would you even know in advance what the "something else" is?

    Say
    trying to take a IOCP completion using a timeout of zero? If we got
    data, we add it to a local queue or something. No blocking.

    You're talking about Win32, consider how
    `GetQueuedCompletionStatus` might be implemented. You may well
    be taking a round-trip through the kernel to do that, which is
    very expensive compared to, say, incrementing a register.

    What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    No. If there is no other work to do, it falls back to lock(). If if did
    too much work, it falls back to lock.

    You're missing the point: there's no good way to determine
    whether _any_ amount of work is "too much".

    Fair enough. But, there is a chance to hit the fast path, so to speak. try_lock fails, then the thread does a call to say, GetQueuedCompletionStatusEx with a timeout of zero, (aka try), if it
    succeeds, it can push the batch into thread local queues, then try the try_lock again and succeeds. So, instead of waiting in the kernel for
    the mutex it did actual work, and god knows how many other threads got
    the mutex in the mean time. So, forward progress is guaranteed. The
    nature of the "tried" work must be known, and if its compatible, so be
    it. If not, so be it. Fair enough?


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Thu Aug 7 08:47:55 2025
    On 8/6/2025 5:04 AM, Dan Cross wrote:
    In article <106udu9$3400b$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 5:38 PM, Dan Cross wrote:
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread >>>>>> fails to acquire the mutex, it can check to see if it has any other work >>>>>> to do instead of just waiting in the kernel doing nothing, or spinning >>>>>> doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some >>>>>> other work? Think of an adaptive mutex. On contention it will spin for a >>>>>> bounded number of times in user space before having to wait in the >>>>>> kernel. Well, instead of spinning, try to do something else, some real >>>>>> work? It will keep the thread hot, doing work instead of just waiting... >>>>>
    Because while its doing something else the lock maybe become free then >>>>> become acquired again leading to a kind of race condition of some threads >>>>
    Nope. A thread can only do something else for a bounded number of times. >>>> So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is
    computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call). What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    Using this pattern, well, can be a nightmare, but can be somewhat
    beneficial at the same time?

    Yeah, so beneficial that it's been codified many times over:
    acquiring a contended blocking mutex yields, so that something
    else can run instead.

    If a programmer knew that a class of
    functions are compatible with the try_lock failed condition, well, why
    not give them a go? Better than spinning doing nothing, or god forbid,
    waiting in the kernel?

    The whole premise of a spinlock is that the critical section
    that it protects is short (like, a few instructions), so the
    overhead of spinning is smaller than the overhead of context
    switching to something else. If that is not true, you shouldn't
    be using a spinlock as your mutex primitive in the first place,
    and a blocking or adaptive mutex is more appropriate. By the
    way, there's nothing at all wrong with blocking in the kernel;
    given a reasonable OS, it's not like if *YOUR THREAD* isn't
    running the CPU will be idle or something.

    My try other work thing still works with short and/or long critical
    sections. Try other work replaces the spin aspect of an adaptive mutex
    with trying to do other "compatible" work. If no other work can be found
    to do, it falls back to a lock() anyway. If it does "too much" work, say
    5 or 10 work items, it locks. try_lock is just there to keep the pump
    running, so to speak...


    But if you still want to avoid blocking when a mutex is
    unavailable, then you've got the idea inverted. Focusing on the
    locking protocol as some kind of generic place to do "other
    work" is too general to be useful, as has been shown. To be
    truly useful, this sort of approach must be coupled with
    knowledge of what a thread can safely do in context, which means
    that you really need to specialize the behavior for the
    _critical section_, not the _mutex_: the programmer knows why
    the thread is trying to acquire a mutex in that case, and what
    other work may or may not be acceptable to do if the mutex isn't
    immediately available. So they can craft the critical section
    to take advantage of that knowledge themselves. This sort of
    technique is well-known, by the way.

    But then it's not going to be particularly general. And you may
    argue that the critical section might be buried deep down in a
    call stack, very far away from the place where the programmer
    can reasonably make a decision about whether it's safe to do
    something or not, so that's a more appropriate place: but that
    reinforces the objections: if the critical section is so far
    away from the point where the programmer knows whether it's safe
    for the thread to do something else, then the programmer doesn't
    really know whether that thing is safe, because the intervening
    calls might have changed conditions so that it's not, so trying
    to plumb that knowledge down to the mutex code is again too
    dangerous to be useful.

    But even if the programmer could safely interpose doing
    "something else" in this way, they may not have full knowledge
    to know whether or not that will cause the thread to block.
    Consider, for example, a program that tries to do something
    innocuous, like zero a a few byte's worth of memory while
    trying to take a lock; what if the page holding the memory to be
    zero'ed has been stolen by the OS in the meantime, and now the
    program (totally unbeknownst to it) incurs a page fault that
    requires reading data from secondary storage to resolve? Not
    only has a single store now blocked your thread in the big scary
    kernel, but it's blocked it for many, many cycles.

    So while this technique is known and used in existing systems,
    it must be done so carefully that it really isn't appropriate as
    a general mechanism.

    carefully is the key concept! Yikes... Shit... However, basically, it
    still boils down to trying other "work" on a spin can keep the thread
    "hot" doing other work, instead of spinning on an adaptive logic of a
    mutex, nothing nothing?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Thu Aug 7 14:44:45 2025
    Am 07.08.2025 um 00:34 schrieb Chris M. Thomasson:

    On 8/6/2025 6:51 AM, Bonita Montero wrote:

    This situation almost never happens.
    It requires that the locking can be delayed an arbitrary time.

    Not an arbitrary time. Its bounded.

    No one actually follows this silly idea.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Fri Aug 8 05:17:42 2025
    On 8/6/2025 9:44 PM, Bonita Montero wrote:
    Am 07.08.2025 um 00:34 schrieb Chris M. Thomasson:

    On 8/6/2025 6:51 AM, Bonita Montero wrote:

    This situation almost never happens.
    It requires that the locking can be delayed an arbitrary time.

    Not an arbitrary time. Its bounded.

    No one actually follows this silly idea.


    I don't think its totally silly. Why spin in an adaptive mutex backoff
    when other work be done? It's akin to a backoff with meaning, not just
    doing nothing.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Fri Aug 8 05:32:56 2025
    On 8/6/2025 9:44 PM, Bonita Montero wrote:
    Am 07.08.2025 um 00:34 schrieb Chris M. Thomasson:

    On 8/6/2025 6:51 AM, Bonita Montero wrote:

    This situation almost never happens.
    It requires that the locking can be delayed an arbitrary time.

    Not an arbitrary time. Its bounded.

    No one actually follows this silly idea.


    Actually, this made me think of an older experiment of mine for a proxy collector using mutexes. It's pretty funny, but works. Humm... If I get
    some more time tonight I might code it up for fun.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Fri Aug 8 05:51:38 2025
    Am 07.08.2025 um 21:17 schrieb Chris M. Thomasson:

    On 8/6/2025 9:44 PM, Bonita Montero wrote:

    No one actually follows this silly idea.

    I don't think its totally silly. ...

    It is.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Fri Aug 8 05:52:13 2025
    On 8/7/2025 12:51 PM, Bonita Montero wrote:
    Am 07.08.2025 um 21:17 schrieb Chris M. Thomasson:

    On 8/6/2025 9:44 PM, Bonita Montero wrote:

    No one actually follows this silly idea.

    I don't think its totally silly. ...

    It is.


    Why? I don't think its 100% silly.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Fri Aug 8 11:41:31 2025
    In article <1070lq1$3lg2n$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/6/2025 4:29 AM, Dan Cross wrote:
    In article <106udpt$3400b$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    [snip]
    No. If there is no other work to do, it falls back to lock(). If if did
    too much work, it falls back to lock.

    You're missing the point: there's no good way to determine
    whether _any_ amount of work is "too much".

    Fair enough. But, there is a chance to hit the fast path, so to speak.

    You literally have no way of knowing that beforehand.

    try_lock fails, then the thread does a call to say, >GetQueuedCompletionStatusEx with a timeout of zero, (aka try), if it >succeeds, it can push the batch into thread local queues, then try the >try_lock again and succeeds.

    You are, again, missing the point. Not only does making a call
    to `GetQueuedCompletionStatusEx` involve a round trip through
    the kernel, in which case you may as well just block in the
    kernel and let another thread run, you seem to be missing the
    specific that IOCP completion is irrelevant, because it is just
    one example.

    So, instead of waiting in the kernel for
    the mutex it did actual work, and god knows how many other threads got
    the mutex in the mean time. So, forward progress is guaranteed. The
    nature of the "tried" work must be known, and if its compatible, so be
    it. If not, so be it. Fair enough?

    No. You keep saying that "forward progress is guaranteed"
    because you bound the total number of times that your locking
    thread can do "something else." But again, the point that you
    are missing is that any given "something else" can itself be
    completely unbounded, possibly in a way that is totally
    unknowable at the time you go to do it; see the lock ordering
    constraint violation I gave earlier as an example: there's no
    way you can know whether that will be problematic until runtime,
    and there's no way you can meaningfully assess "compatibility"
    in general.

    So even if you bound the number of times you'll do "something
    else", since you have no guarantee that ANY instance of other
    work is itself bounded, you can't make any guarantees about
    whether the scheme as a whole is bounded.

    And if it's really just, "for this specific critical section, if
    you fail to immediately acquire the lock, go try this other,
    very specific thing known to be safe in this specific context,
    and then try again...." then as I've said, this is well-known,
    but is also wholly unoriginal and thus uninteresting.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Fri Aug 8 11:49:29 2025
    In article <1070m2s$3lg2n$4@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/6/2025 5:04 AM, Dan Cross wrote:
    In article <106udu9$3400b$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 5:38 PM, Dan Cross wrote:
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread >>>>>>> fails to acquire the mutex, it can check to see if it has any other work
    to do instead of just waiting in the kernel doing nothing, or spinning >>>>>>> doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some >>>>>>> other work? Think of an adaptive mutex. On contention it will spin for a
    bounded number of times in user space before having to wait in the >>>>>>> kernel. Well, instead of spinning, try to do something else, some real >>>>>>> work? It will keep the thread hot, doing work instead of just waiting...

    Because while its doing something else the lock maybe become free then >>>>>> become acquired again leading to a kind of race condition of some threads

    Nope. A thread can only do something else for a bounded number of times. >>>>> So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is
    computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call). What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    Using this pattern, well, can be a nightmare, but can be somewhat
    beneficial at the same time?

    Yeah, so beneficial that it's been codified many times over:
    acquiring a contended blocking mutex yields, so that something
    else can run instead.

    If a programmer knew that a class of
    functions are compatible with the try_lock failed condition, well, why
    not give them a go? Better than spinning doing nothing, or god forbid,
    waiting in the kernel?

    The whole premise of a spinlock is that the critical section
    that it protects is short (like, a few instructions), so the
    overhead of spinning is smaller than the overhead of context
    switching to something else. If that is not true, you shouldn't
    be using a spinlock as your mutex primitive in the first place,
    and a blocking or adaptive mutex is more appropriate. By the
    way, there's nothing at all wrong with blocking in the kernel;
    given a reasonable OS, it's not like if *YOUR THREAD* isn't
    running the CPU will be idle or something.

    My try other work thing still works with short and/or long critical >sections. Try other work replaces the spin aspect of an adaptive mutex
    with trying to do other "compatible" work. If no other work can be found
    to do, it falls back to a lock() anyway. If it does "too much" work, say
    5 or 10 work items, it locks. try_lock is just there to keep the pump >running, so to speak...

    Again, just bounding the number of times you do "other work" is
    insufficient to guarantee forward progress. See the example of
    trying to recursively acquire a held mutex, leading to deadlock.
    The issue here is not that you only do things 5, 10, or 1000
    times, but that there is no meaningful way you could assess
    "compatibility" (not without solving the halting problem anyway)
    and so any given bit of "other work" could basically deadlock
    the whole thing.

    If your "other work" can take arbitrarily long, how is this
    mechanism any better than just letting the thread that wants to
    acquire the mutex block and letting another thread chew through
    your work queue?

    But if you still want to avoid blocking when a mutex is
    unavailable, then you've got the idea inverted. Focusing on the
    locking protocol as some kind of generic place to do "other
    work" is too general to be useful, as has been shown. To be
    truly useful, this sort of approach must be coupled with
    knowledge of what a thread can safely do in context, which means
    that you really need to specialize the behavior for the
    _critical section_, not the _mutex_: the programmer knows why
    the thread is trying to acquire a mutex in that case, and what
    other work may or may not be acceptable to do if the mutex isn't
    immediately available. So they can craft the critical section
    to take advantage of that knowledge themselves. This sort of
    technique is well-known, by the way.

    But then it's not going to be particularly general. And you may
    argue that the critical section might be buried deep down in a
    call stack, very far away from the place where the programmer
    can reasonably make a decision about whether it's safe to do
    something or not, so that's a more appropriate place: but that
    reinforces the objections: if the critical section is so far
    away from the point where the programmer knows whether it's safe
    for the thread to do something else, then the programmer doesn't
    really know whether that thing is safe, because the intervening
    calls might have changed conditions so that it's not, so trying
    to plumb that knowledge down to the mutex code is again too
    dangerous to be useful.

    But even if the programmer could safely interpose doing
    "something else" in this way, they may not have full knowledge
    to know whether or not that will cause the thread to block.
    Consider, for example, a program that tries to do something
    innocuous, like zero a a few byte's worth of memory while
    trying to take a lock; what if the page holding the memory to be
    zero'ed has been stolen by the OS in the meantime, and now the
    program (totally unbeknownst to it) incurs a page fault that
    requires reading data from secondary storage to resolve? Not
    only has a single store now blocked your thread in the big scary
    kernel, but it's blocked it for many, many cycles.

    So while this technique is known and used in existing systems,
    it must be done so carefully that it really isn't appropriate as
    a general mechanism.

    carefully is the key concept! Yikes... Shit... However, basically, it
    still boils down to trying other "work" on a spin can keep the thread
    "hot" doing other work, instead of spinning on an adaptive logic of a
    mutex, nothing nothing?

    Keeping a thread "hot" without being able to make any sort of
    meaningful guarantee about the viability of the scheme as a
    general mechanism is not useful, when considering the scheme as
    a general mechanism.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Fri Aug 8 11:51:57 2025
    In article <1070laa$3lg2n$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/6/2025 6:51 AM, Bonita Montero wrote:
    Am 30.07.2025 um 07:54 schrieb Chris M. Thomasson:

    This is using the idea of trying to do other work while a mutex is
    contended. ...

    This situation almost never happens.
    It requires that the locking can be delayed an arbitrary time.

    Not an arbitrary time. Its bounded.

    The number of times you try to do "other work" may be bounded.
    But I don't see any why you think you can meaningfully assert
    that the work itself is usefully bounded. So no, it is not
    guaranteed to be bounded, in which case you must assume it is
    unbounded.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Fri Aug 8 13:52:19 2025
    On 8/7/2025 6:41 PM, Dan Cross wrote:
    In article <1070lq1$3lg2n$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/6/2025 4:29 AM, Dan Cross wrote:
    In article <106udpt$3400b$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    [snip]
    No. If there is no other work to do, it falls back to lock(). If if did >>>> too much work, it falls back to lock.

    You're missing the point: there's no good way to determine
    whether _any_ amount of work is "too much".

    Fair enough. But, there is a chance to hit the fast path, so to speak.

    You literally have no way of knowing that beforehand.

    try_lock fails, then the thread does a call to say,
    GetQueuedCompletionStatusEx with a timeout of zero, (aka try), if it
    succeeds, it can push the batch into thread local queues, then try the
    try_lock again and succeeds.

    You are, again, missing the point. Not only does making a call
    to `GetQueuedCompletionStatusEx` involve a round trip through
    the kernel, in which case you may as well just block in the
    kernel and let another thread run, you seem to be missing the
    specific that IOCP completion is irrelevant, because it is just
    one example.

    So, instead of waiting in the kernel for
    the mutex it did actual work, and god knows how many other threads got
    the mutex in the mean time. So, forward progress is guaranteed. The
    nature of the "tried" work must be known, and if its compatible, so be
    it. If not, so be it. Fair enough?

    No. You keep saying that "forward progress is guaranteed"
    because you bound the total number of times that your locking
    thread can do "something else." But again, the point that you
    are missing is that any given "something else" can itself be
    completely unbounded, possibly in a way that is totally
    unknowable at the time you go to do it; see the lock ordering
    constraint violation I gave earlier as an example: there's no
    way you can know whether that will be problematic until runtime,
    and there's no way you can meaningfully assess "compatibility"
    in general.

    So even if you bound the number of times you'll do "something
    else", since you have no guarantee that ANY instance of other
    work is itself bounded, you can't make any guarantees about
    whether the scheme as a whole is bounded.

    And if it's really just, "for this specific critical section, if
    you fail to immediately acquire the lock, go try this other,
    very specific thing known to be safe in this specific context,
    and then try again...." then as I've said, this is well-known,
    but is also wholly unoriginal and thus uninteresting.

    So be it. That's fine. I just thought it might be, sometimes, beneficial
    in "certain", rather rare, scenarios. Well, shit happens.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Fri Aug 8 13:59:52 2025
    On 8/7/2025 6:49 PM, Dan Cross wrote:
    In article <1070m2s$3lg2n$4@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/6/2025 5:04 AM, Dan Cross wrote:
    In article <106udu9$3400b$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 5:38 PM, Dan Cross wrote:
    In article <106u31a$31k65$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/5/2025 12:27 AM, Muttley@DastardlyHQ.org wrote:
    On Mon, 4 Aug 2025 12:34:08 -0700
    "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wibbled:
    [snip]
    This already works with multiple threads, no problem. But, if a thread >>>>>>>> fails to acquire the mutex, it can check to see if it has any other work
    to do instead of just waiting in the kernel doing nothing, or spinning >>>>>>>> doing nothing... Make sense to you?

    The idea behind what you're trying to do is well-understood.

    In fact, this is what generally happens when you try to acquire
    a contended, blocking mutex: if the mutex is currently locked by
    some other thread, you mark the acquiring thread as blocked
    waiting on the mutex, and then yield control back to a scheduler
    or something; eventually the other thread will finish what it
    was doing and release the mutex, but part of releasing the mutex
    and making it available again is marking threads that were
    blocked on it runnable, thus opening them up to be scheduled
    again, where they can once again try to acquire the mutex.

    The twist here seems to be that, instead of immediately
    yielding, for some bounded number of times, you look at a work
    queue and try to find something else for the acquiring thread to
    do while the lock you want is unavailable. Regardless, the
    effect is more or less the same.

    Personally, I see little benefit, and a number of potential
    pitfalls. In particular, I see no reason why the bundled bits
    of work in this scheme can't cause any number of lock ordering
    violations and lead to all sorts of deadlock scenarios. Suppose
    for example, that I acquire some mutex, A, and then go to
    acquire a second mutex, B: B is currently held by some other
    thread, so I begin to spin, but I see that there is an item in
    my work queue, so I go to do that. The first thing that work
    item does is try to acquire mutex A, which I'm currently
    holding, leading to deadlock against A.

    One could perhaps assert that these work items are not allowed
    to take or hold locks, which could address this particular
    failure mode, but it's unclear how one might enforce this in
    general, and there may well be other, similar failure modes.

    [snip]
    The idea is instead of letting it wait, why not let it try to do some >>>>>>>> other work? Think of an adaptive mutex. On contention it will spin for a
    bounded number of times in user space before having to wait in the >>>>>>>> kernel. Well, instead of spinning, try to do something else, some real >>>>>>>> work? It will keep the thread hot, doing work instead of just waiting...

    Because while its doing something else the lock maybe become free then >>>>>>> become acquired again leading to a kind of race condition of some threads

    Nope. A thread can only do something else for a bounded number of times. >>>>>> So, its starvation free. No race condition.

    This is simply not true. Suppose that the "something else" is
    computationally intensive, or blocks the thread somehow (say, by
    executing a blocking system call). What if the "something else"
    just spins in an infinte loop, waiting for some event? Just
    because you bound the number of times you do "something else"
    does not mean you are free of starvation, because what the other
    thing actual does matters.

    Using this pattern, well, can be a nightmare, but can be somewhat
    beneficial at the same time?

    Yeah, so beneficial that it's been codified many times over:
    acquiring a contended blocking mutex yields, so that something
    else can run instead.

    If a programmer knew that a class of
    functions are compatible with the try_lock failed condition, well, why >>>> not give them a go? Better than spinning doing nothing, or god forbid, >>>> waiting in the kernel?

    The whole premise of a spinlock is that the critical section
    that it protects is short (like, a few instructions), so the
    overhead of spinning is smaller than the overhead of context
    switching to something else. If that is not true, you shouldn't
    be using a spinlock as your mutex primitive in the first place,
    and a blocking or adaptive mutex is more appropriate. By the
    way, there's nothing at all wrong with blocking in the kernel;
    given a reasonable OS, it's not like if *YOUR THREAD* isn't
    running the CPU will be idle or something.

    My try other work thing still works with short and/or long critical
    sections. Try other work replaces the spin aspect of an adaptive mutex
    with trying to do other "compatible" work. If no other work can be found
    to do, it falls back to a lock() anyway. If it does "too much" work, say
    5 or 10 work items, it locks. try_lock is just there to keep the pump
    running, so to speak...

    Again, just bounding the number of times you do "other work" is
    insufficient to guarantee forward progress. See the example of
    trying to recursively acquire a held mutex, leading to deadlock.
    The issue here is not that you only do things 5, 10, or 1000
    times, but that there is no meaningful way you could assess
    "compatibility" (not without solving the halting problem anyway)
    and so any given bit of "other work" could basically deadlock
    the whole thing.

    If your "other work" can take arbitrarily long, how is this
    mechanism any better than just letting the thread that wants to
    acquire the mutex block and letting another thread chew through
    your work queue?

    But if you still want to avoid blocking when a mutex is
    unavailable, then you've got the idea inverted. Focusing on the
    locking protocol as some kind of generic place to do "other
    work" is too general to be useful, as has been shown. To be
    truly useful, this sort of approach must be coupled with
    knowledge of what a thread can safely do in context, which means
    that you really need to specialize the behavior for the
    _critical section_, not the _mutex_: the programmer knows why
    the thread is trying to acquire a mutex in that case, and what
    other work may or may not be acceptable to do if the mutex isn't
    immediately available. So they can craft the critical section
    to take advantage of that knowledge themselves. This sort of
    technique is well-known, by the way.

    But then it's not going to be particularly general. And you may
    argue that the critical section might be buried deep down in a
    call stack, very far away from the place where the programmer
    can reasonably make a decision about whether it's safe to do
    something or not, so that's a more appropriate place: but that
    reinforces the objections: if the critical section is so far
    away from the point where the programmer knows whether it's safe
    for the thread to do something else, then the programmer doesn't
    really know whether that thing is safe, because the intervening
    calls might have changed conditions so that it's not, so trying
    to plumb that knowledge down to the mutex code is again too
    dangerous to be useful.

    But even if the programmer could safely interpose doing
    "something else" in this way, they may not have full knowledge
    to know whether or not that will cause the thread to block.
    Consider, for example, a program that tries to do something
    innocuous, like zero a a few byte's worth of memory while
    trying to take a lock; what if the page holding the memory to be
    zero'ed has been stolen by the OS in the meantime, and now the
    program (totally unbeknownst to it) incurs a page fault that
    requires reading data from secondary storage to resolve? Not
    only has a single store now blocked your thread in the big scary
    kernel, but it's blocked it for many, many cycles.

    So while this technique is known and used in existing systems,
    it must be done so carefully that it really isn't appropriate as
    a general mechanism.

    carefully is the key concept! Yikes... Shit... However, basically, it
    still boils down to trying other "work" on a spin can keep the thread
    "hot" doing other work, instead of spinning on an adaptive logic of a
    mutex, nothing nothing?

    Keeping a thread "hot" without being able to make any sort of
    meaningful guarantee about the viability of the scheme as a
    general mechanism is not useful, when considering the scheme as
    a general mechanism.

    general mechanism? No. Oh no. I am no trying to do that at all. How
    about a sometimes it might be okay type of scenario? Argh! My mind keeps
    on thinking of other work that will not spin off into never never land,
    the nightmare thing I mentioned. It will not deadlock, actually, not
    sure how it could deadlock in this highly special realm, anyway... That
    call to a try IOCP means that is has the "chance" to gain data, checking
    a thread local queues has a chance to have other work while the mutex is
    in contention anyway via try_lock fail? Oh my.... I am grasping at
    straws here.. But, it still might be okay for certain scenarios?

    Actually, way back, 20-25 years ago when I was messing around with proxy collectors... I had a base case that used mutexes only. No fancy
    atomics, ect... Pre C++11, ect... It worked. If a per thread mutex
    try_lock failed it meant a reaper thread got a hold of it, and it should
    lock its next generation of mutexes. all per thread. This would allow
    for a RCU type of setup using mutexes only. Pretty fun.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Fri Aug 8 14:01:49 2025
    On 8/7/2025 6:51 PM, Dan Cross wrote:
    In article <1070laa$3lg2n$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/6/2025 6:51 AM, Bonita Montero wrote:
    Am 30.07.2025 um 07:54 schrieb Chris M. Thomasson:

    This is using the idea of trying to do other work while a mutex is
    contended. ...

    This situation almost never happens.
    It requires that the locking can be delayed an arbitrary time.

    Not an arbitrary time. Its bounded.

    The number of times you try to do "other work" may be bounded.
    But I don't see any why you think you can meaningfully assert
    that the work itself is usefully bounded. So no, it is not
    guaranteed to be bounded, in which case you must assume it is
    unbounded.

    Humm... Good point. Say the work was a try to pop off a lock-free queue,
    then stuff that result into a thread local queue. Or, if the work is "compatible", well, not call into unknown user code or something like
    that, then, execute it. Well, the mutex is contended anyway?Ahhh shit.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Fri Aug 8 14:08:43 2025
    On 8/7/2025 9:01 PM, Chris M. Thomasson wrote:
    On 8/7/2025 6:51 PM, Dan Cross wrote:
    In article <1070laa$3lg2n$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/6/2025 6:51 AM, Bonita Montero wrote:
    Am 30.07.2025 um 07:54 schrieb Chris M. Thomasson:

    This is using the idea of trying to do other work while a mutex is
    contended. ...

    This situation almost never happens.
    It requires that the locking can be delayed an arbitrary time.

    Not an arbitrary time. Its bounded.

    The number of times you try to do "other work" may be bounded.
    But I don't see any why you think you can meaningfully assert
    that the work itself is usefully bounded. So no, it is not
    guaranteed to be bounded, in which case you must assume it is
    unbounded.

    Humm... Good point. Say the work was a try to pop off a lock-free queue, then stuff that result into a thread local queue. Or, if the work is "compatible", well, not call into unknown user code or something like
    that, then, execute it. Well, the mutex is contended anyway?Ahhh shit.

    Oh... Its been many years. But I just thought of my test bench. Mutex
    proxy vs lock-free proxy for a poor mans RCU. If a thread hit a failure
    on a try_lock() it means its in transition, so it should switch to the
    other set of per-thread locks, and try_lock again. A reapear thread
    would switch a threads lock index, then take the previous lock. Once a
    reaper thread held all of the threads previous locks, it was deemed a quiescent state.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Sat Aug 9 19:17:25 2025
    In article <1073snp$en4a$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/7/2025 6:49 PM, Dan Cross wrote:
    In article <1070m2s$3lg2n$4@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    [snip]
    carefully is the key concept! Yikes... Shit... However, basically, it
    still boils down to trying other "work" on a spin can keep the thread
    "hot" doing other work, instead of spinning on an adaptive logic of a
    mutex, nothing nothing?

    Keeping a thread "hot" without being able to make any sort of
    meaningful guarantee about the viability of the scheme as a
    general mechanism is not useful, when considering the scheme as
    a general mechanism.

    general mechanism? No. Oh no. I am no trying to do that at all. How
    about a sometimes it might be okay type of scenario? Argh! My mind keeps
    on thinking of other work that will not spin off into never never land,
    the nightmare thing I mentioned. It will not deadlock, actually, not
    sure how it could deadlock in this highly special realm, anyway... That
    call to a try IOCP means that is has the "chance" to gain data, checking
    a thread local queues has a chance to have other work while the mutex is
    in contention anyway via try_lock fail? Oh my.... I am grasping at
    straws here.. But, it still might be okay for certain scenarios?

    Yes, you are grasping at straws.

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    Actually, way back, 20-25 years ago when I was messing around with proxy >collectors... I had a base case that used mutexes only. No fancy
    atomics, ect... Pre C++11, ect... It worked. If a per thread mutex
    try_lock failed it meant a reaper thread got a hold of it, and it should >lock its next generation of mutexes. all per thread. This would allow
    for a RCU type of setup using mutexes only. Pretty fun.

    That vague, incomplete description sounds nothing like how RCU
    works.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sat Aug 9 19:52:49 2025
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to
    be done elsewhere must be able to be omitted completely if necessary,
    and if not, it must be short enough that it doesn't interfere with
    waiting for the mutex.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Sun Aug 10 02:08:27 2025
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>,
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to
    be done elsewhere must be able to be omitted completely if necessary,
    and if not, it must be short enough that it doesn't interfere with
    waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being
    a function of the critsec. It's going to be things like, "if I
    fail to acquire the scheduler lock, then increment this per-core
    atomic counter that's measuring contention...." sort of thing.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sun Aug 10 03:44:35 2025
    On 8/9/2025 2:17 AM, Dan Cross wrote:
    In article <1073snp$en4a$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/7/2025 6:49 PM, Dan Cross wrote:
    In article <1070m2s$3lg2n$4@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    [snip]
    carefully is the key concept! Yikes... Shit... However, basically, it
    still boils down to trying other "work" on a spin can keep the thread
    "hot" doing other work, instead of spinning on an adaptive logic of a
    mutex, nothing nothing?

    Keeping a thread "hot" without being able to make any sort of
    meaningful guarantee about the viability of the scheme as a
    general mechanism is not useful, when considering the scheme as
    a general mechanism.

    general mechanism? No. Oh no. I am no trying to do that at all. How
    about a sometimes it might be okay type of scenario? Argh! My mind keeps
    on thinking of other work that will not spin off into never never land,
    the nightmare thing I mentioned. It will not deadlock, actually, not
    sure how it could deadlock in this highly special realm, anyway... That
    call to a try IOCP means that is has the "chance" to gain data, checking
    a thread local queues has a chance to have other work while the mutex is
    in contention anyway via try_lock fail? Oh my.... I am grasping at
    straws here.. But, it still might be okay for certain scenarios?

    Yes, you are grasping at straws.

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    Oh well. At least we had a nice conversation about it. thanks. :^)


    Actually, way back, 20-25 years ago when I was messing around with proxy
    collectors... I had a base case that used mutexes only. No fancy
    atomics, ect... Pre C++11, ect... It worked. If a per thread mutex
    try_lock failed it meant a reaper thread got a hold of it, and it should
    lock its next generation of mutexes. all per thread. This would allow
    for a RCU type of setup using mutexes only. Pretty fun.

    That vague, incomplete description sounds nothing like how RCU
    works.

    It's a way to get a proxy collector (RCU like) using two sets of
    per-thread locks. It was an older test bench to see how a mutex version compared against a lock-free version. Have you taken a look at my proxy collector? Here is an older one:

    https://pastebin.com/raw/CYZ78gVj


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sun Aug 10 03:48:16 2025
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>,
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to
    be done elsewhere must be able to be omitted completely if necessary,
    and if not, it must be short enough that it doesn't interfere with
    waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being
    a function of the critsec. It's going to be things like, "if I
    fail to acquire the scheduler lock, then increment this per-core
    atomic counter that's measuring contention...." sort of thing.

    More grasping at straws and/or trying to breath underwater without scuba gear... The other work is very specialized. It can be as simple as
    processing a per-thread local queue or something. Just something that
    can act like a backoff that does real work in a case of contention. Sigh.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sun Aug 10 04:00:33 2025
    On 8/9/2025 10:44 AM, Chris M. Thomasson wrote:
    On 8/9/2025 2:17 AM, Dan Cross wrote:
    In article <1073snp$en4a$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/7/2025 6:49 PM, Dan Cross wrote:
    In article <1070m2s$3lg2n$4@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    [snip]
    carefully is the key concept! Yikes... Shit... However, basically, it >>>>> still boils down to trying other "work" on a spin can keep the thread >>>>> "hot" doing other work, instead of spinning on an adaptive logic of a >>>>> mutex, nothing nothing?

    Keeping a thread "hot" without being able to make any sort of
    meaningful guarantee about the viability of the scheme as a
    general mechanism is not useful, when considering the scheme as
    a general mechanism.

    general mechanism? No. Oh no. I am no trying to do that at all. How
    about a sometimes it might be okay type of scenario? Argh! My mind keeps >>> on thinking of other work that will not spin off into never never land,
    the nightmare thing I mentioned. It will not deadlock, actually, not
    sure how it could deadlock in this highly special realm, anyway... That
    call to a try IOCP means that is has the "chance" to gain data, checking >>> a thread local queues has a chance to have other work while the mutex is >>> in contention anyway via try_lock fail? Oh my.... I am grasping at
    straws here.. But, it still might be okay for certain scenarios?

    Yes, you are grasping at straws.

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    Oh well. At least we had a nice conversation about it. thanks. :^)


    Actually, way back, 20-25 years ago when I was messing around with proxy >>> collectors... I had a base case that used mutexes only. No fancy
    atomics, ect... Pre C++11, ect... It worked. If a per thread mutex
    try_lock failed it meant a reaper thread got a hold of it, and it should >>> lock its next generation of mutexes. all per thread. This would allow
    for a RCU type of setup using mutexes only. Pretty fun.

    That vague, incomplete description sounds nothing like how RCU
    works.

    It's a way to get a proxy collector (RCU like) using two sets of per-
    thread locks. It was an older test bench to see how a mutex version
    compared against a lock-free version. Have you taken a look at my proxy collector? Here is an older one:

    https://pastebin.com/raw/CYZ78gVj


    The test in there allows a lock-free stack to be iterated without any
    worry about a node being destroyed during iteration. Also, the reads do
    not interfere with the writes and vice versa. So, it is RCU-like.
    Actually, it eliminates the need for an ABA counter such that the
    lock-free stack can use a single word. It's a fun experiment. When you
    get really bored, give it a go? Thanks Dan. Its pretty fun, well, to me anyway. Thanks.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Sun Aug 10 13:08:44 2025
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>,
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to
    be done elsewhere must be able to be omitted completely if necessary,
    and if not, it must be short enough that it doesn't interfere with
    waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being
    a function of the critsec. It's going to be things like, "if I
    fail to acquire the scheduler lock, then increment this per-core
    atomic counter that's measuring contention...." sort of thing.

    More grasping at straws and/or trying to breath underwater without scuba >gear... The other work is very specialized. It can be as simple as >processing a per-thread local queue or something. Just something that
    can act like a backoff that does real work in a case of contention. Sigh.

    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to
    keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Mon Aug 11 19:04:50 2025
    Am 09.08.2025 um 19:48 schrieb Chris M. Thomasson:

    More grasping at straws and/or trying to breath underwater without scuba gear... The other work is very specialized. It can be as simple as processing a per-thread local queue or something. Just something that
    can act like a backoff that does real work in a case of contention. Sigh.

    Interesting that you can't think of anything specific about
    the task that could otherwise be done, just vague stuff.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 12 06:30:08 2025
    On 8/11/2025 2:04 AM, Bonita Montero wrote:
    Am 09.08.2025 um 19:48 schrieb Chris M. Thomasson:

    More grasping at straws and/or trying to breath underwater without
    scuba gear... The other work is very specialized. It can be as simple
    as processing a per-thread local queue or something. Just something
    that can act like a backoff that does real work in a case of
    contention. Sigh.

    Interesting that you can't think of anything specific about
    the task that could otherwise be done, just vague stuff.

    I gave some quick examples, perhaps you missed them. It could be
    batching thread local queues, checking to see if an GetQueuedCompletionStatusEx (timeout 0) succeeds, perhaps something that
    does not call into user code, stuff like that... Wrt batching, think if
    a server worker thread has separate local queues for accepts, connects,
    sends, recvs... Batching is beneficial, and GetQueuedCompletionStatusEx (GQCSEX) can return multiple io's at once. There is an old paper about
    it called stagedserver:

    https://www.cs.cmu.edu/~StagedDB/papers/CMU-CS-02-113.pdf

    So, stuffing the results from GQCSEX into local queues allows for this.

    The other work is going to be specialized. So, a programmer can say
    well, if the try_lock fails, lets try this instead.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 12 06:37:37 2025
    On 8/9/2025 8:08 PM, Dan Cross wrote:
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>,
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to
    be done elsewhere must be able to be omitted completely if necessary,
    and if not, it must be short enough that it doesn't interfere with
    waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being
    a function of the critsec. It's going to be things like, "if I
    fail to acquire the scheduler lock, then increment this per-core
    atomic counter that's measuring contention...." sort of thing.

    More grasping at straws and/or trying to breath underwater without scuba
    gear... The other work is very specialized. It can be as simple as
    processing a per-thread local queue or something. Just something that
    can act like a backoff that does real work in a case of contention. Sigh.

    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    Well, that per-thread local queue can be for organization, maintenance, sending the results to a "logic" thread, ect. Think of a server io
    thread that takes the io completions and organizes them into local
    queues. These io threads do not call into user logic, or processing wrt
    say, parsing HTTP, or some protocol. So, some work that can be used
    after a try_lock fails can be to push the local queues to the logic threads.


    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to
    keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    But why sleep when the thread can do some real work? Argh. Grasping
    again. Feels like I am drowning. Shit! ;^o

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Aug 12 18:23:19 2025
    Am 11.08.2025 um 22:30 schrieb Chris M. Thomasson:

    I gave some quick examples, perhaps you missed them. It could be
    batching thread local queues, checking to see if an GetQueuedCompletionStatusEx (timeout 0) succeeds, ...

    GetQueuedCompletionStatusEx() is an expensive kernel call, not something
    you do casually. Even a Sleep( 0 ), which is equivalent to a std:: this_thread::yield(), costs about 1,000 clock cycles on a modern CPU.
    And GetQueuedCompletionStatusEx() isn't a function whose execution can
    be arbitrarily delayed or even prevented altogether. In other words:
    You're simply overthinking.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 12 18:31:43 2025
    On 8/12/2025 1:23 AM, Bonita Montero wrote:
    Am 11.08.2025 um 22:30 schrieb Chris M. Thomasson:

    I gave some quick examples, perhaps you missed them. It could be
    batching thread local queues, checking to see if an
    GetQueuedCompletionStatusEx (timeout 0) succeeds, ...

    GetQueuedCompletionStatusEx() is an expensive kernel call, not something
    you do casually. Even a Sleep( 0 ), which is equivalent to a std:: this_thread::yield(), costs about 1,000 clock cycles on a modern CPU.
    And GetQueuedCompletionStatusEx() isn't a function whose execution can
    be arbitrarily delayed or even prevented altogether. In other words:
    You're simply overthinking.

    Its seems quite fine though. try_lock fails... Sometimes go for a GetQueuedCompletionStatusEx with a 0 timeout. Vs just going into the
    kernel anyway for the contention. Try some local queues before trying GetQueuedCompletionStatusEx a couple of times in the backoff, Or
    spinning ala adaptive mutex logic doing nothing anyway... If it succeeds
    we get to sort the results into their per thread queues, if not, we
    lock. If it succeeds too (too much work) many times we lock. If try lock
    does not fail, well we got the damn lock anyway. So be it?



    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Aug 12 18:39:41 2025
    Am 12.08.2025 um 10:31 schrieb Chris M. Thomasson:

    Its seems quite fine though. try_lock fails... Sometimes go for a GetQueuedCompletionStatusEx with a 0 timeout.

    I've tried that:

    #include <Windows.h>
    #include <iostream>
    #include <chrono>

    using namespace std;
    using namespace chrono;

    int main()
    {
    HANDLE hFile = CreateFileA( "bla.txt", GENERIC_READ | GENERIC_WRITE, 0,
    nullptr, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL );
    if( hFile == INVALID_HANDLE_VALUE )
    return EXIT_FAILURE;
    HANDLE hIocp = CreateIoCompletionPort( hFile, NULL, NULL, 1 );
    if( !hIocp )
    return EXIT_FAILURE;
    auto start = high_resolution_clock::now();
    for( size_t r = 1'000'000; r; --r )
    {
    SetLastError( NO_ERROR );
    DWORD dwTransferred;
    ULONG_PTR ulpKey = 0;
    OVERLAPPED *pOl = nullptr;
    if( !GetQueuedCompletionStatus( hIocp, &dwTransferred, &ulpKey, &pOl,
    0 ) && GetLastError() != WAIT_TIMEOUT )
    return EXIT_FAILURE;
    }
    cout << (double)duration_cast<nanoseconds>( high_resolution_clock::now() - start ).count() / 1.0e6 << endl;
    }

    On my Zen4-CPU the immediately timeouted GetQueuedCompletionStatus() is
    about 226ms. Do you still think you're right ? You've too much phantasy.



    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 12 18:45:18 2025
    On 8/12/2025 1:39 AM, Bonita Montero wrote:
    Am 12.08.2025 um 10:31 schrieb Chris M. Thomasson:

    Its seems quite fine though. try_lock fails... Sometimes go for a
    GetQueuedCompletionStatusEx with a 0 timeout.

    I've tried that:

    #include <Windows.h>
    #include <iostream>
    #include <chrono>

    using namespace std;
    using namespace chrono;

    int main()
    {
    HANDLE hFile = CreateFileA( "bla.txt", GENERIC_READ |
    GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL );
    if( hFile == INVALID_HANDLE_VALUE )
    return EXIT_FAILURE;
    HANDLE hIocp = CreateIoCompletionPort( hFile, NULL, NULL, 1 );
    if( !hIocp )
    return EXIT_FAILURE;
    auto start = high_resolution_clock::now();
    for( size_t r = 1'000'000; r; --r )
    {
    SetLastError( NO_ERROR );
    DWORD dwTransferred;
    ULONG_PTR ulpKey = 0;
    OVERLAPPED *pOl = nullptr;
    if( !GetQueuedCompletionStatus( hIocp, &dwTransferred, &ulpKey, &pOl, 0 ) && GetLastError() != WAIT_TIMEOUT )
    return EXIT_FAILURE;
    }
    cout <<
    (double)duration_cast<nanoseconds>( high_resolution_clock::now() -
    start ).count() / 1.0e6 << endl;
    }

    On my Zen4-CPU the immediately timeouted GetQueuedCompletionStatus() is
    about 226ms. Do you still think you're right ? You've too much phantasy.



    So, other threads could have tried the mutex by then, or shit happens. Hopefully the system would be loaded to where the probability of GetQueuedCompletionStatusEx returning something would be high. Or,
    perhaps try per-thread local data-structures first for a couple of spins failing on try_lock, then try a GetQueuedCompletionStatusEx, then say
    oh my try_lock still failed, lock.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Aug 12 18:56:59 2025
    Am 12.08.2025 um 10:45 schrieb Chris M. Thomasson:

    So, other threads could have tried the mutex by then, or shit happens.

    The idea is simply nonsense.

    Hopefully the system would be loaded to where the probability of GetQueuedCompletionStatusEx returning something would be high. Or,
    perhaps try per-thread local data-structures first for a couple of spins failing on try_lock, then try a GetQueuedCompletionStatusEx, then say
    oh my try_lock still failed, lock.



    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 12 19:14:39 2025
    On 8/12/2025 1:56 AM, Bonita Montero wrote:
    Am 12.08.2025 um 10:45 schrieb Chris M. Thomasson:

    So, other threads could have tried the mutex by then, or shit happens.

    The idea is simply nonsense.

    Are you 100% sure about that?

    Thread A try_lock failed. It tries and fails on a GQCSEX. In the mean
    time threads B...G have taken the lock, done their thing, and released
    it. Or the other path. Thread A tries again, fails, nothing to do, or
    back off exceeded, then calls lock.

    Thread A try_lock failed. GQCSEX succeeds and it gets to sort its io completions into per-thread queues, ect, then try_lock again. Other
    threads could have already locked and unlocked the mutex, but the thread
    A did real work, and its try_lock succeeds! It did not have to spin
    doing nothing and it did not have to wait in the kernel doing nothing,
    ect, ect...



    Hopefully the system would be loaded to where the probability of
    GetQueuedCompletionStatusEx returning something would be high. Or,
    perhaps try per-thread local data-structures first for a couple of
    spins failing on try_lock, then try a GetQueuedCompletionStatusEx,
    then say oh my try_lock still failed, lock.




    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Tue Aug 12 23:08:21 2025
    Am 12.08.2025 um 11:14 schrieb Chris M. Thomasson:
    On 8/12/2025 1:56 AM, Bonita Montero wrote:
    Am 12.08.2025 um 10:45 schrieb Chris M. Thomasson:

    So, other threads could have tried the mutex by then, or shit happens.

    The idea is simply nonsense.

    Are you 100% sure about that?

    You need a task that is some nanoseconds only and that can be completely omitted if locking succeeds. That never happens.



    Thread A try_lock failed. It tries and fails on a GQCSEX. In the mean
    time threads B...G have taken the lock, done their thing, and released
    it. Or the other path. Thread A tries again, fails, nothing to do, or
    back off exceeded, then calls lock.

    Thread A try_lock failed. GQCSEX succeeds and it gets to sort its io completions into per-thread queues, ect, then try_lock again. Other
    threads could have already locked and unlocked the mutex, but the thread
    A did real work, and its try_lock succeeds! It did not have to spin
    doing nothing and it did not have to wait in the kernel doing nothing,
    ect, ect...



    Hopefully the system would be loaded to where the probability of
    GetQueuedCompletionStatusEx returning something would be high. Or,
    perhaps try per-thread local data-structures first for a couple of
    spins failing on try_lock, then try a GetQueuedCompletionStatusEx,
    then say oh my try_lock still failed, lock.





    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Wed Aug 13 21:41:35 2025
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 8:08 PM, Dan Cross wrote:
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>,
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to >>>>> be done elsewhere must be able to be omitted completely if necessary, >>>>> and if not, it must be short enough that it doesn't interfere with
    waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being
    a function of the critsec. It's going to be things like, "if I
    fail to acquire the scheduler lock, then increment this per-core
    atomic counter that's measuring contention...." sort of thing.

    More grasping at straws and/or trying to breath underwater without scuba >>> gear... The other work is very specialized. It can be as simple as
    processing a per-thread local queue or something. Just something that
    can act like a backoff that does real work in a case of contention. Sigh. >>
    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    Well, that per-thread local queue can be for organization, maintenance, >sending the results to a "logic" thread, ect. Think of a server io
    thread that takes the io completions and organizes them into local
    queues. These io threads do not call into user logic, or processing wrt
    say, parsing HTTP, or some protocol. So, some work that can be used
    after a try_lock fails can be to push the local queues to the logic threads.

    This, yet again, seems to be where you don't understand the
    issue at stake here.

    You can _probably_ find _any number of things_ that you can do
    while looping over `try_lock`. I don't care about the specific
    examples: they obviously exist.

    But what you _cannot_ do, and what makes this sort of scheme
    fail, is know that _all_ such work is safe. Unless you can wave
    a magic wand and solve the halting problem, you won't be able to
    know that some jerk won't send you "work" that amounts to a
    non-terminating infinite loop. You won't be able to know that
    some other jerk hasn't sent you "work" that causes you to
    deadlock trying to take a mutex you already hold. Etc.

    If you _ever_ open yourself up to accepting "work" on some kind
    of queue, where the types of all work that can possibly be sent
    to you is not known in advance _in some way that can be enforced
    in code_, then your scheme fails. And if you do have some way
    to enforce those constraints, then the scheme is neither novel
    nor particularly interesting.

    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to
    keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    But why sleep when the thread can do some real work?

    Because the OS (or even a user-level thread scheduler, or
    language runtime, or whatever) can find work to usefully do on
    that CPU, _without_ the downsides mentioned above. So you lose
    nothing but gain correctness and stability.

    Argh. Grasping
    again. Feels like I am drowning. Shit! ;^o

    Perhaps stop doing that, then. It's clear you are not going to
    find a way to make whatever partially developed idea you have
    work.

    It's ok to be wrong. It's less ok to keep trying to convince
    others that you are right.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Wed Aug 13 21:45:42 2025
    In article <107eu5g$33jcr$5@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/12/2025 1:23 AM, Bonita Montero wrote:
    Am 11.08.2025 um 22:30 schrieb Chris M. Thomasson:

    I gave some quick examples, perhaps you missed them. It could be
    batching thread local queues, checking to see if an
    GetQueuedCompletionStatusEx (timeout 0) succeeds, ...

    GetQueuedCompletionStatusEx() is an expensive kernel call, not something
    you do casually. Even a Sleep( 0 ), which is equivalent to a std::
    this_thread::yield(), costs about 1,000 clock cycles on a modern CPU.
    And GetQueuedCompletionStatusEx() isn't a function whose execution can
    be arbitrarily delayed or even prevented altogether. In other words:
    You're simply overthinking.

    Its seems quite fine though. try_lock fails... Sometimes go for a >GetQueuedCompletionStatusEx with a 0 timeout. Vs just going into the
    kernel anyway for the contention. Try some local queues before trying >GetQueuedCompletionStatusEx a couple of times in the backoff, Or
    spinning ala adaptive mutex logic doing nothing anyway... If it succeeds
    we get to sort the results into their per thread queues, if not, we
    lock. If it succeeds too (too much work) many times we lock. If try lock >does not fail, well we got the damn lock anyway. So be it?

    I don't think you have a good handle on the relative cost of
    these operations.

    You seem to be against spending a few cycles spinning, or
    against paying the one time cost of going to sleep in the kernel
    until your mutex is available, but willing to burn thousands of
    cycles going into the kernel over and over again to see if an IO
    port becomes ready so that you can keep your thread "hot".

    That's, frankly, not at all a good tradeoff.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Thu Aug 14 03:07:39 2025
    Am 13.08.2025 um 13:45 schrieb Dan Cross:

    I don't think you have a good handle on the relative cost of
    these operations.

    You seem to be against spending a few cycles spinning, or
    against paying the one time cost of going to sleep in the kernel
    until your mutex is available, but willing to burn thousands of
    cycles going into the kernel over and over again to see if an IO
    port becomes ready so that you can keep your thread "hot".

    That's, frankly, not at all a good tradeoff.

    Chris has too much phantasy.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Scott Lurndal@3:633/280.2 to All on Thu Aug 14 03:31:20 2025
    Reply-To: slp53@pacbell.net

    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 13.08.2025 um 13:45 schrieb Dan Cross:

    I don't think you have a good handle on the relative cost of
    these operations.

    You seem to be against spending a few cycles spinning, or
    against paying the one time cost of going to sleep in the kernel
    until your mutex is available, but willing to burn thousands of
    cycles going into the kernel over and over again to see if an IO
    port becomes ready so that you can keep your thread "hot".

    That's, frankly, not at all a good tradeoff.

    Chris has too much phantasy.

    Du bist zu kritisch.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: UsenetServer - www.usenetserver.com (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Thu Aug 14 05:41:27 2025
    On 8/13/2025 10:07 AM, Bonita Montero wrote:
    Am 13.08.2025 um 13:45 schrieb Dan Cross:

    I don't think you have a good handle on the relative cost of
    these operations.

    You seem to be against spending a few cycles spinning, or
    against paying the one time cost of going to sleep in the kernel
    until your mutex is available, but willing to burn thousands of
    cycles going into the kernel over and over again to see if an IO
    port becomes ready so that you can keep your thread "hot".

    That's, frankly, not at all a good tradeoff.

    Chris has too much phantasy.


    Shit can happen! ;^)

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sat Aug 16 03:00:15 2025
    On 8/13/2025 10:31 AM, Scott Lurndal wrote:
    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 13.08.2025 um 13:45 schrieb Dan Cross:

    I don't think you have a good handle on the relative cost of
    these operations.

    You seem to be against spending a few cycles spinning, or
    against paying the one time cost of going to sleep in the kernel
    until your mutex is available, but willing to burn thousands of
    cycles going into the kernel over and over again to see if an IO
    port becomes ready so that you can keep your thread "hot".

    That's, frankly, not at all a good tradeoff.

    Chris has too much phantasy.

    Du bist zu kritisch.

    Well, the pattern only shines when the other work is actually compatible
    with it. For instance, if the other work blocks on say, io, well, that
    would be bad.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sat Aug 16 10:28:24 2025
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin... https://pastebin.com/raw/CYZ78gVj

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sat Aug 16 10:30:42 2025
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 8:08 PM, Dan Cross wrote:
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>,
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that
    fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to >>>>>> be done elsewhere must be able to be omitted completely if necessary, >>>>>> and if not, it must be short enough that it doesn't interfere with >>>>>> waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being
    a function of the critsec. It's going to be things like, "if I
    fail to acquire the scheduler lock, then increment this per-core
    atomic counter that's measuring contention...." sort of thing.

    More grasping at straws and/or trying to breath underwater without scuba >>>> gear... The other work is very specialized. It can be as simple as
    processing a per-thread local queue or something. Just something that
    can act like a backoff that does real work in a case of contention. Sigh. >>>
    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    Well, that per-thread local queue can be for organization, maintenance,
    sending the results to a "logic" thread, ect. Think of a server io
    thread that takes the io completions and organizes them into local
    queues. These io threads do not call into user logic, or processing wrt
    say, parsing HTTP, or some protocol. So, some work that can be used
    after a try_lock fails can be to push the local queues to the logic threads.

    This, yet again, seems to be where you don't understand the
    issue at stake here.

    You can _probably_ find _any number of things_ that you can do
    while looping over `try_lock`. I don't care about the specific
    examples: they obviously exist.

    But what you _cannot_ do, and what makes this sort of scheme
    fail, is know that _all_ such work is safe. Unless you can wave
    a magic wand and solve the halting problem, you won't be able to
    know that some jerk won't send you "work" that amounts to a
    non-terminating infinite loop. You won't be able to know that
    some other jerk hasn't sent you "work" that causes you to
    deadlock trying to take a mutex you already hold. Etc.

    If you _ever_ open yourself up to accepting "work" on some kind
    of queue, where the types of all work that can possibly be sent
    to you is not known in advance _in some way that can be enforced
    in code_, then your scheme fails. And if you do have some way
    to enforce those constraints, then the scheme is neither novel
    nor particularly interesting.

    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to
    keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    But why sleep when the thread can do some real work?

    Because the OS (or even a user-level thread scheduler, or
    language runtime, or whatever) can find work to usefully do on
    that CPU, _without_ the downsides mentioned above. So you lose
    nothing but gain correctness and stability.

    Argh. Grasping
    again. Feels like I am drowning. Shit! ;^o

    Perhaps stop doing that, then. It's clear you are not going to
    find a way to make whatever partially developed idea you have
    work.

    It should be okay if the other work is okay with it?


    It's ok to be wrong. It's less ok to keep trying to convince
    others that you are right.

    It just seems to be okay, well, after a try_lock fails try to do
    something that is _compatible_ instead of something like an adaptive
    mutex? Shit. Yikes!

    There I go again. Sorry.

    [...]

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sat Aug 16 14:36:54 2025
    On 8/12/2025 6:08 AM, Bonita Montero wrote:
    Am 12.08.2025 um 11:14 schrieb Chris M. Thomasson:
    On 8/12/2025 1:56 AM, Bonita Montero wrote:
    Am 12.08.2025 um 10:45 schrieb Chris M. Thomasson:

    So, other threads could have tried the mutex by then, or shit happens. >>>
    The idea is simply nonsense.

    Are you 100% sure about that?

    You need a task that is some nanoseconds only and that can be completely omitted if locking succeeds. That never happens.

    Not totally true. Other _compatible_ work can be akin to a backoff, say
    in an adaptive mutex. It's far a few between, but it can be usefull in
    certian scenarios. When a try_lock fails it means another thread is
    making progress.





    Thread A try_lock failed. It tries and fails on a GQCSEX. In the mean
    time threads B...G have taken the lock, done their thing, and released
    it. Or the other path. Thread A tries again, fails, nothing to do, or
    back off exceeded, then calls lock.

    Thread A try_lock failed. GQCSEX succeeds and it gets to sort its io
    completions into per-thread queues, ect, then try_lock again. Other
    threads could have already locked and unlocked the mutex, but the
    thread A did real work, and its try_lock succeeds! It did not have to
    spin doing nothing and it did not have to wait in the kernel doing
    nothing, ect, ect...



    Hopefully the system would be loaded to where the probability of
    GetQueuedCompletionStatusEx returning something would be high. Or,
    perhaps try per-thread local data-structures first for a couple of
    spins failing on try_lock, then try a GetQueuedCompletionStatusEx,
    then say oh my try_lock still failed, lock.






    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sat Aug 16 18:13:11 2025
    Am 16.08.2025 um 06:36 schrieb Chris M. Thomasson:

    On 8/12/2025 6:08 AM, Bonita Montero wrote:

    You need a task that is some nanoseconds only and that can be completely
    omitted if locking succeeds. That never happens.

    Not totally true. Other _compatible_ work can be akin to a backoff, say
    in an adaptive mutex. It's far a few between, but it can be usefull in certian scenarios. When a try_lock fails it means another thread is
    making progress.

    Show me a *practical* example of a task that is short in the mentioned dimensions (a few nanoseconds) and that can be completely omitted.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sat Aug 16 18:56:41 2025
    On 8/16/2025 1:13 AM, Bonita Montero wrote:
    Am 16.08.2025 um 06:36 schrieb Chris M. Thomasson:

    On 8/12/2025 6:08 AM, Bonita Montero wrote:

    You need a task that is some nanoseconds only and that can be completely >>> omitted if locking succeeds. That never happens.

    Not totally true. Other _compatible_ work can be akin to a backoff,
    say in an adaptive mutex. It's far a few between, but it can be
    usefull in certian scenarios. When a try_lock fails it means another
    thread is making progress.

    Show me a *practical* example of a task that is short in the mentioned dimensions (a few nanoseconds) and that can be completely omitted.

    Well, why does it have to be a few nanoseconds? Anyway, say pop from a
    stack using atomic exchange?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sat Aug 16 19:05:57 2025
    Am 16.08.2025 um 10:56 schrieb Chris M. Thomasson:
    On 8/16/2025 1:13 AM, Bonita Montero wrote:
    Am 16.08.2025 um 06:36 schrieb Chris M. Thomasson:

    On 8/12/2025 6:08 AM, Bonita Montero wrote:

    You need a task that is some nanoseconds only and that can be
    completely
    omitted if locking succeeds. That never happens.

    Not totally true. Other _compatible_ work can be akin to a backoff,
    say in an adaptive mutex. It's far a few between, but it can be
    usefull in certian scenarios. When a try_lock fails it means another
    thread is making progress.

    Show me a *practical* example of a task that is short in the mentioned
    dimensions (a few nanoseconds) and that can be completely omitted.

    Well, why does it have to be a few nanoseconds?

    Yes, to delay the locking o the mutex not too long.
    Show me a paper desribing your idea.

    Anyway, say pop from a stack using atomic exchange?

    And this can be completely omitted ?
    Your idea is simply silly.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sat Aug 16 19:21:05 2025
    Am 07.08.2025 um 21:52 schrieb Chris M. Thomasson:
    On 8/7/2025 12:51 PM, Bonita Montero wrote:
    Am 07.08.2025 um 21:17 schrieb Chris M. Thomasson:

    On 8/6/2025 9:44 PM, Bonita Montero wrote:

    No one actually follows this silly idea.

    I don't think its totally silly. ...

    It is.


    Why? I don't think its 100% silly.

    I've already told that: The task needs to be some nanoseconds only
    (similar to a PAUSE-instruction) to delay the locking not so long
    and the task must be able to be completely omitted, i.e. it may be
    excecuted nevey. Both in combination never happens.
    Show me a paper about your idea. If that would really work someone
    else should have written a paper about that.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sun Aug 17 06:22:43 2025
    On 8/16/2025 2:21 AM, Bonita Montero wrote:
    Am 07.08.2025 um 21:52 schrieb Chris M. Thomasson:
    On 8/7/2025 12:51 PM, Bonita Montero wrote:
    Am 07.08.2025 um 21:17 schrieb Chris M. Thomasson:

    On 8/6/2025 9:44 PM, Bonita Montero wrote:

    No one actually follows this silly idea.

    I don't think its totally silly. ...

    It is.


    Why? I don't think its 100% silly.

    I've already told that: The task needs to be some nanoseconds only
    (similar to a PAUSE-instruction) to delay the locking not so long
    and the task must be able to be completely omitted, i.e. it may be
    excecuted nevey. Both in combination never happens.
    Show me a paper about your idea. If that would really work someone
    else should have written a paper about that.


    The backoff that does productive work does not necessarily need that
    mutex, now, now, now... It's doing other real work in the mean time,
    during contention?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sun Aug 17 06:31:47 2025
    On 8/16/2025 2:05 AM, Bonita Montero wrote:
    Am 16.08.2025 um 10:56 schrieb Chris M. Thomasson:
    On 8/16/2025 1:13 AM, Bonita Montero wrote:
    Am 16.08.2025 um 06:36 schrieb Chris M. Thomasson:

    On 8/12/2025 6:08 AM, Bonita Montero wrote:

    You need a task that is some nanoseconds only and that can be
    completely
    omitted if locking succeeds. That never happens.

    Not totally true. Other _compatible_ work can be akin to a backoff,
    say in an adaptive mutex. It's far a few between, but it can be
    usefull in certian scenarios. When a try_lock fails it means another
    thread is making progress.

    Show me a *practical* example of a task that is short in the mentioned
    dimensions (a few nanoseconds) and that can be completely omitted.

    Well, why does it have to be a few nanoseconds?

    Yes, to delay the locking o the mutex not too long.

    To delay possibly doing other real work. Think of messing with the
    backoff count of an adaptive mutex that spins in userspace doing nothing before resorting to the kernel?


    Show me a paper desribing your idea.

    Humm... Need to search. Maybe a paper on what not to do? lol. Anyway, if try_lock fails it means another thread is doing real work, agreed? So,
    why should the thread that got a try_lock failure be banned from trying
    to do other real work? Humm...


    Anyway, say pop from a stack using atomic exchange?

    And this can be completely omitted ?
    Your idea is simply silly.

    Popping an atomic stack using a single exchange is fine and normal. That
    right there can be a productive backoff if the result of the pop was non-null... ?

    The backoff that does productive work does not necessarily need that
    mutex, now, now, now... It's doing other real work in the mean time,
    during contention? Kind of fair "enough" is a sense? Thanks.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sun Aug 17 11:59:39 2025
    Am 16.08.2025 um 22:22 schrieb Chris M. Thomasson:
    On 8/16/2025 2:21 AM, Bonita Montero wrote:
    Am 07.08.2025 um 21:52 schrieb Chris M. Thomasson:
    On 8/7/2025 12:51 PM, Bonita Montero wrote:
    Am 07.08.2025 um 21:17 schrieb Chris M. Thomasson:

    On 8/6/2025 9:44 PM, Bonita Montero wrote:

    No one actually follows this silly idea.

    I don't think its totally silly. ...

    It is.


    Why? I don't think its 100% silly.

    I've already told that: The task needs to be some nanoseconds only
    (similar to a PAUSE-instruction) to delay the locking not so long
    and the task must be able to be completely omitted, i.e. it may be
    excecuted nevey. Both in combination never happens.
    Show me a paper about your idea. If that would really work someone
    else should have written a paper about that.


    The backoff that does productive work does not necessarily need that
    mutex, now, now, now... It's doing other real work in the mean time,
    during contention?

    Your idea is total nonsense.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Sun Aug 17 16:53:48 2025
    On 8/16/2025 6:59 PM, Bonita Montero wrote:
    Am 16.08.2025 um 22:22 schrieb Chris M. Thomasson:
    On 8/16/2025 2:21 AM, Bonita Montero wrote:
    Am 07.08.2025 um 21:52 schrieb Chris M. Thomasson:
    On 8/7/2025 12:51 PM, Bonita Montero wrote:
    Am 07.08.2025 um 21:17 schrieb Chris M. Thomasson:

    On 8/6/2025 9:44 PM, Bonita Montero wrote:

    No one actually follows this silly idea.

    I don't think its totally silly. ...

    It is.


    Why? I don't think its 100% silly.

    I've already told that: The task needs to be some nanoseconds only
    (similar to a PAUSE-instruction) to delay the locking not so long
    and the task must be able to be completely omitted, i.e. it may be
    excecuted nevey. Both in combination never happens.
    Show me a paper about your idea. If that would really work someone
    else should have written a paper about that.


    The backoff that does productive work does not necessarily need that
    mutex, now, now, now... It's doing other real work in the mean time,
    during contention?

    Your idea is total nonsense.


    I still don't think its 100% nonsense.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sun Aug 17 18:37:10 2025
    Am 17.08.2025 um 08:53 schrieb Chris M. Thomasson:

    Your idea is total nonsense.

    I still don't think its 100% nonsense.

    I think some people had this idea already and have withdrawn it because
    of what I said. It simply doesn't work because the task has to be able
    to be totally omitted and the task has to be nanoseconds-short.
    The best thing is to poll with PAUSE instructions and to use the gaps
    the PAUSE instruction leavs with some other code on the same core.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Sun Aug 17 22:50:04 2025
    Am 16.08.2025 um 22:31 schrieb Chris M. Thomasson:

    On 8/16/2025 2:05 AM, Bonita Montero wrote:
    And this can be completely omitted ?
    Your idea is simply silly.

    Popping an atomic stack using a single exchange is fine and normal. That right there can be a productive backoff if the result of the pop was non-null... ?

    Is this an answer to my question ?

    No one has published your idea before; it's nonsense.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Mon Aug 18 06:43:23 2025
    On 8/17/2025 5:50 AM, Bonita Montero wrote:
    Am 16.08.2025 um 22:31 schrieb Chris M. Thomasson:

    On 8/16/2025 2:05 AM, Bonita Montero wrote:
    And this can be completely omitted ?
    Your idea is simply silly.

    Popping an atomic stack using a single exchange is fine and normal.
    That right there can be a productive backoff if the result of the pop
    was non-null... ?

    Is this an answer to my question ?

    Yeah.


    No one has published your idea before; it's nonsense.


    99% nonsense or 99.(9)% nonsense? ;^)

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Tue Aug 19 06:25:11 2025
    In article <107ojb9$1e84t$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin... >https://pastebin.com/raw/CYZ78gVj

    No need, I'm afraid.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Tue Aug 19 06:26:10 2025
    In article <107ojfk$1e84t$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 8:08 PM, Dan Cross wrote:
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>,
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that >>>>>>>> fails, does something else, for decades. The idea is neither
    new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to >>>>>>> be done elsewhere must be able to be omitted completely if necessary, >>>>>>> and if not, it must be short enough that it doesn't interfere with >>>>>>> waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being
    a function of the critsec. It's going to be things like, "if I
    fail to acquire the scheduler lock, then increment this per-core
    atomic counter that's measuring contention...." sort of thing.

    More grasping at straws and/or trying to breath underwater without scuba >>>>> gear... The other work is very specialized. It can be as simple as
    processing a per-thread local queue or something. Just something that >>>>> can act like a backoff that does real work in a case of contention. Sigh. >>>>
    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    Well, that per-thread local queue can be for organization, maintenance,
    sending the results to a "logic" thread, ect. Think of a server io
    thread that takes the io completions and organizes them into local
    queues. These io threads do not call into user logic, or processing wrt
    say, parsing HTTP, or some protocol. So, some work that can be used
    after a try_lock fails can be to push the local queues to the logic threads.

    This, yet again, seems to be where you don't understand the
    issue at stake here.

    You can _probably_ find _any number of things_ that you can do
    while looping over `try_lock`. I don't care about the specific
    examples: they obviously exist.

    But what you _cannot_ do, and what makes this sort of scheme
    fail, is know that _all_ such work is safe. Unless you can wave
    a magic wand and solve the halting problem, you won't be able to
    know that some jerk won't send you "work" that amounts to a
    non-terminating infinite loop. You won't be able to know that
    some other jerk hasn't sent you "work" that causes you to
    deadlock trying to take a mutex you already hold. Etc.

    If you _ever_ open yourself up to accepting "work" on some kind
    of queue, where the types of all work that can possibly be sent
    to you is not known in advance _in some way that can be enforced
    in code_, then your scheme fails. And if you do have some way
    to enforce those constraints, then the scheme is neither novel
    nor particularly interesting.

    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to
    keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    But why sleep when the thread can do some real work?

    Because the OS (or even a user-level thread scheduler, or
    language runtime, or whatever) can find work to usefully do on
    that CPU, _without_ the downsides mentioned above. So you lose
    nothing but gain correctness and stability.

    Argh. Grasping
    again. Feels like I am drowning. Shit! ;^o

    Perhaps stop doing that, then. It's clear you are not going to
    find a way to make whatever partially developed idea you have
    work.

    It should be okay if the other work is okay with it?

    Again: you have no way of knowing that "the other work is okay
    with it".

    It's ok to be wrong. It's less ok to keep trying to convince
    others that you are right.

    It just seems to be okay, well, after a try_lock fails try to do
    something that is _compatible_ instead of something like an adaptive
    mutex? Shit. Yikes!

    There I go again. Sorry.

    [...]

    Please stop.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 06:34:35 2025
    On 8/18/2025 1:25 PM, Dan Cross wrote:
    In article <107ojb9$1e84t$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin...
    https://pastebin.com/raw/CYZ78gVj

    No need, I'm afraid.

    You don't like proxy collectors? Or you think mine is shit?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 06:39:07 2025
    On 8/18/2025 1:26 PM, Dan Cross wrote:
    In article <107ojfk$1e84t$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 8:08 PM, Dan Cross wrote:
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>, >>>>>>> Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that >>>>>>>>> fails, does something else, for decades. The idea is neither >>>>>>>>> new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to >>>>>>>> be done elsewhere must be able to be omitted completely if necessary, >>>>>>>> and if not, it must be short enough that it doesn't interfere with >>>>>>>> waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being >>>>>>> a function of the critsec. It's going to be things like, "if I
    fail to acquire the scheduler lock, then increment this per-core >>>>>>> atomic counter that's measuring contention...." sort of thing.

    More grasping at straws and/or trying to breath underwater without scuba >>>>>> gear... The other work is very specialized. It can be as simple as >>>>>> processing a per-thread local queue or something. Just something that >>>>>> can act like a backoff that does real work in a case of contention. Sigh.

    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    Well, that per-thread local queue can be for organization, maintenance, >>>> sending the results to a "logic" thread, ect. Think of a server io
    thread that takes the io completions and organizes them into local
    queues. These io threads do not call into user logic, or processing wrt >>>> say, parsing HTTP, or some protocol. So, some work that can be used
    after a try_lock fails can be to push the local queues to the logic threads.

    This, yet again, seems to be where you don't understand the
    issue at stake here.

    You can _probably_ find _any number of things_ that you can do
    while looping over `try_lock`. I don't care about the specific
    examples: they obviously exist.

    But what you _cannot_ do, and what makes this sort of scheme
    fail, is know that _all_ such work is safe. Unless you can wave
    a magic wand and solve the halting problem, you won't be able to
    know that some jerk won't send you "work" that amounts to a
    non-terminating infinite loop. You won't be able to know that
    some other jerk hasn't sent you "work" that causes you to
    deadlock trying to take a mutex you already hold. Etc.

    If you _ever_ open yourself up to accepting "work" on some kind
    of queue, where the types of all work that can possibly be sent
    to you is not known in advance _in some way that can be enforced
    in code_, then your scheme fails. And if you do have some way
    to enforce those constraints, then the scheme is neither novel
    nor particularly interesting.

    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to
    keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    But why sleep when the thread can do some real work?

    Because the OS (or even a user-level thread scheduler, or
    language runtime, or whatever) can find work to usefully do on
    that CPU, _without_ the downsides mentioned above. So you lose
    nothing but gain correctness and stability.

    Argh. Grasping
    again. Feels like I am drowning. Shit! ;^o

    Perhaps stop doing that, then. It's clear you are not going to
    find a way to make whatever partially developed idea you have
    work.

    It should be okay if the other work is okay with it?

    Again: you have no way of knowing that "the other work is okay
    with it".

    Sure you can in highly controlled scenarios? A programmer can say, this
    type of work can be done in this condition because the programmer knows
    what the work consists of... I listed a few of them before. I am not
    going for some sort of general case type of thing.


    It's ok to be wrong. It's less ok to keep trying to convince
    others that you are right.

    It just seems to be okay, well, after a try_lock fails try to do
    something that is _compatible_ instead of something like an adaptive
    mutex? Shit. Yikes!

    There I go again. Sorry.

    [...]

    Please stop.

    It sure seems like it cannot be 100% wrong all the time. Having trouble
    seeing that.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Tue Aug 19 06:39:49 2025
    In article <10802os$3bdl8$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:25 PM, Dan Cross wrote:
    In article <107ojb9$1e84t$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin...
    https://pastebin.com/raw/CYZ78gVj

    No need, I'm afraid.

    You don't like proxy collectors? Or you think mine is shit?

    Sorry, I'm just not sure you're a useful source of code like
    this. It's subtle and requires a lot of in-depth understanding
    of very thorny issues that it doesn't strike me you have a good
    handle on.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Tue Aug 19 06:44:42 2025
    In article <108031c$3bdl8$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:26 PM, Dan Cross wrote:
    In article <107ojfk$1e84t$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 8:08 PM, Dan Cross wrote:
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>, >>>>>>>> Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that >>>>>>>>>> fails, does something else, for decades. The idea is neither >>>>>>>>>> new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to >>>>>>>>> be done elsewhere must be able to be omitted completely if necessary, >>>>>>>>> and if not, it must be short enough that it doesn't interfere with >>>>>>>>> waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places
    where the "something else" is well-known, which implies it being >>>>>>>> a function of the critsec. It's going to be things like, "if I >>>>>>>> fail to acquire the scheduler lock, then increment this per-core >>>>>>>> atomic counter that's measuring contention...." sort of thing.

    More grasping at straws and/or trying to breath underwater without scuba
    gear... The other work is very specialized. It can be as simple as >>>>>>> processing a per-thread local queue or something. Just something that >>>>>>> can act like a backoff that does real work in a case of contention. Sigh.

    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    Well, that per-thread local queue can be for organization, maintenance, >>>>> sending the results to a "logic" thread, ect. Think of a server io
    thread that takes the io completions and organizes them into local
    queues. These io threads do not call into user logic, or processing wrt >>>>> say, parsing HTTP, or some protocol. So, some work that can be used
    after a try_lock fails can be to push the local queues to the logic threads.

    This, yet again, seems to be where you don't understand the
    issue at stake here.

    You can _probably_ find _any number of things_ that you can do
    while looping over `try_lock`. I don't care about the specific
    examples: they obviously exist.

    But what you _cannot_ do, and what makes this sort of scheme
    fail, is know that _all_ such work is safe. Unless you can wave
    a magic wand and solve the halting problem, you won't be able to
    know that some jerk won't send you "work" that amounts to a
    non-terminating infinite loop. You won't be able to know that
    some other jerk hasn't sent you "work" that causes you to
    deadlock trying to take a mutex you already hold. Etc.

    If you _ever_ open yourself up to accepting "work" on some kind
    of queue, where the types of all work that can possibly be sent
    to you is not known in advance _in some way that can be enforced
    in code_, then your scheme fails. And if you do have some way
    to enforce those constraints, then the scheme is neither novel
    nor particularly interesting.

    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to
    keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    But why sleep when the thread can do some real work?

    Because the OS (or even a user-level thread scheduler, or
    language runtime, or whatever) can find work to usefully do on
    that CPU, _without_ the downsides mentioned above. So you lose
    nothing but gain correctness and stability.

    Argh. Grasping
    again. Feels like I am drowning. Shit! ;^o

    Perhaps stop doing that, then. It's clear you are not going to
    find a way to make whatever partially developed idea you have
    work.

    It should be okay if the other work is okay with it?

    Again: you have no way of knowing that "the other work is okay
    with it".

    Sure you can in highly controlled scenarios? A programmer can say, this
    type of work can be done in this condition because the programmer knows
    what the work consists of... I listed a few of them before. I am not
    going for some sort of general case type of thing.


    It's ok to be wrong. It's less ok to keep trying to convince
    others that you are right.

    It just seems to be okay, well, after a try_lock fails try to do
    something that is _compatible_ instead of something like an adaptive
    mutex? Shit. Yikes!

    There I go again. Sorry.

    [...]

    Please stop.

    It sure seems like it cannot be 100% wrong all the time. Having trouble >seeing that.

    It's already in the above quoted text. The relevant section is
    here:

    |You can _probably_ find _any number of things_ that you can do
    |while looping over `try_lock`. I don't care about the specific
    |examples: they obviously exist.
    |
    |But what you _cannot_ do, and what makes this sort of scheme
    |fail, is know that _all_ such work is safe. Unless you can wave
    |a magic wand and solve the halting problem, you won't be able to
    |know that some jerk won't send you "work" that amounts to a
    |non-terminating infinite loop. You won't be able to know that
    |some other jerk hasn't sent you "work" that causes you to
    |deadlock trying to take a mutex you already hold. Etc.
    |
    |If you _ever_ open yourself up to accepting "work" on some kind
    |of queue, where the types of all work that can possibly be sent
    |to you is not known in advance _in some way that can be enforced
    |in code_, then your scheme fails. And if you do have some way
    |to enforce those constraints, then the scheme is neither novel
    |nor particularly interesting.

    Just saying, "yay! I can do something while spinning on a lock!"
    is so vaccuously obvious that it's simply uninteresting; people
    have done such things for many, many years. Your error is in
    trying to extrapolate that to "other" work.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 07:06:24 2025
    On 8/18/2025 1:39 PM, Dan Cross wrote:
    In article <10802os$3bdl8$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:25 PM, Dan Cross wrote:
    In article <107ojb9$1e84t$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin...
    https://pastebin.com/raw/CYZ78gVj

    No need, I'm afraid.

    You don't like proxy collectors? Or you think mine is shit?

    Sorry, I'm just not sure you're a useful source of code like
    this. It's subtle and requires a lot of in-depth understanding
    of very thorny issues that it doesn't strike me you have a good
    handle on.

    Really? Oh well, shit happens. Well, at least have you seen Joe Seighs
    proxy collectors based on his most excellent atomic_ptr? Been working
    with lock/wait free algos for decades, and Sun even gave me a SunFire
    T2000 server with my vZoom project. I found the winner page on the way
    back machine:

    https://web.archive.org/web/20070620081114/https://coolthreads.dev.java.net/




    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 07:08:09 2025
    On 8/18/2025 1:44 PM, Dan Cross wrote:
    In article <108031c$3bdl8$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:26 PM, Dan Cross wrote:
    In article <107ojfk$1e84t$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 8:08 PM, Dan Cross wrote:
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>, >>>>>>>>> Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that >>>>>>>>>>> fails, does something else, for decades. The idea is neither >>>>>>>>>>> new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to
    be done elsewhere must be able to be omitted completely if necessary,
    and if not, it must be short enough that it doesn't interfere with >>>>>>>>>> waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places >>>>>>>>> where the "something else" is well-known, which implies it being >>>>>>>>> a function of the critsec. It's going to be things like, "if I >>>>>>>>> fail to acquire the scheduler lock, then increment this per-core >>>>>>>>> atomic counter that's measuring contention...." sort of thing. >>>>>>>>
    More grasping at straws and/or trying to breath underwater without scuba
    gear... The other work is very specialized. It can be as simple as >>>>>>>> processing a per-thread local queue or something. Just something that >>>>>>>> can act like a backoff that does real work in a case of contention. Sigh.

    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    Well, that per-thread local queue can be for organization, maintenance, >>>>>> sending the results to a "logic" thread, ect. Think of a server io >>>>>> thread that takes the io completions and organizes them into local >>>>>> queues. These io threads do not call into user logic, or processing wrt >>>>>> say, parsing HTTP, or some protocol. So, some work that can be used >>>>>> after a try_lock fails can be to push the local queues to the logic threads.

    This, yet again, seems to be where you don't understand the
    issue at stake here.

    You can _probably_ find _any number of things_ that you can do
    while looping over `try_lock`. I don't care about the specific
    examples: they obviously exist.

    But what you _cannot_ do, and what makes this sort of scheme
    fail, is know that _all_ such work is safe. Unless you can wave
    a magic wand and solve the halting problem, you won't be able to
    know that some jerk won't send you "work" that amounts to a
    non-terminating infinite loop. You won't be able to know that
    some other jerk hasn't sent you "work" that causes you to
    deadlock trying to take a mutex you already hold. Etc.

    If you _ever_ open yourself up to accepting "work" on some kind
    of queue, where the types of all work that can possibly be sent
    to you is not known in advance _in some way that can be enforced
    in code_, then your scheme fails. And if you do have some way
    to enforce those constraints, then the scheme is neither novel
    nor particularly interesting.

    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to >>>>>>> keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    But why sleep when the thread can do some real work?

    Because the OS (or even a user-level thread scheduler, or
    language runtime, or whatever) can find work to usefully do on
    that CPU, _without_ the downsides mentioned above. So you lose
    nothing but gain correctness and stability.

    Argh. Grasping
    again. Feels like I am drowning. Shit! ;^o

    Perhaps stop doing that, then. It's clear you are not going to
    find a way to make whatever partially developed idea you have
    work.

    It should be okay if the other work is okay with it?

    Again: you have no way of knowing that "the other work is okay
    with it".

    Sure you can in highly controlled scenarios? A programmer can say, this
    type of work can be done in this condition because the programmer knows
    what the work consists of... I listed a few of them before. I am not
    going for some sort of general case type of thing.


    It's ok to be wrong. It's less ok to keep trying to convince
    others that you are right.

    It just seems to be okay, well, after a try_lock fails try to do
    something that is _compatible_ instead of something like an adaptive
    mutex? Shit. Yikes!

    There I go again. Sorry.

    [...]

    Please stop.

    It sure seems like it cannot be 100% wrong all the time. Having trouble
    seeing that.

    It's already in the above quoted text. The relevant section is
    here:

    |You can _probably_ find _any number of things_ that you can do
    |while looping over `try_lock`. I don't care about the specific
    |examples: they obviously exist.
    |
    |But what you _cannot_ do, and what makes this sort of scheme
    |fail, is know that _all_ such work is safe. Unless you can wave
    |a magic wand and solve the halting problem, you won't be able to
    |know that some jerk won't send you "work" that amounts to a
    |non-terminating infinite loop. You won't be able to know that
    |some other jerk hasn't sent you "work" that causes you to
    |deadlock trying to take a mutex you already hold. Etc.
    |
    |If you _ever_ open yourself up to accepting "work" on some kind
    |of queue, where the types of all work that can possibly be sent
    |to you is not known in advance _in some way that can be enforced
    |in code_, then your scheme fails. And if you do have some way
    |to enforce those constraints, then the scheme is neither novel
    |nor particularly interesting.

    Just saying, "yay! I can do something while spinning on a lock!"
    is so vaccuously obvious that it's simply uninteresting; people
    have done such things for many, many years. Your error is in
    trying to extrapolate that to "other" work.

    So be it. Although, this convo gave this group a little action, so to
    speak? :^)

    Anyway, I have a lot of experience with lock/wait free algos.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 07:28:22 2025
    On 8/18/2025 2:06 PM, Chris M. Thomasson wrote:
    On 8/18/2025 1:39 PM, Dan Cross wrote:
    In article <10802os$3bdl8$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:25 PM, Dan Cross wrote:
    In article <107ojb9$1e84t$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin...
    https://pastebin.com/raw/CYZ78gVj

    No need, I'm afraid.

    You don't like proxy collectors? Or you think mine is shit?

    Sorry, I'm just not sure you're a useful source of code like
    this. It's subtle and requires a lot of in-depth understanding
    of very thorny issues that it doesn't strike me you have a good
    handle on.

    Really? Oh well, shit happens. Well, at least have you seen Joe Seighs
    proxy collectors based on his most excellent atomic_ptr? Been working
    with lock/wait free algos for decades, and Sun even gave me a SunFire
    T2000 server with my vZoom project. I found the winner page on the way
    back machine:

    https://web.archive.org/web/20070620081114/https:// coolthreads.dev.java.net/



    Fwiw, I found one of my long past older projects on the way back machine
    that is still referenced by my friend who created Relacy:

    https://web.archive.org/web/20071008213108/http://appcore.home.comcast.net/

    https://web.archive.org/web/20060214112539/http://appcore.home.comcast.net/appcore/src/cpu/i686/ac_i686_masm_asm.html

    Here is the reference:

    https://www.1024cores.net/home/lock-free-algorithms/links

    There are more, but I seemed to have forgot about them.

    For some reason I am having trouble getting to the old link to c.p.t,
    heck back when in beta:

    https://web.archive.org/web/20071008213108/http://groups-beta.google.com/group/comp.programming.threads/msg/423df394a0370fa6



    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 07:33:33 2025
    On 8/18/2025 1:39 PM, Dan Cross wrote:
    In article <10802os$3bdl8$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:25 PM, Dan Cross wrote:
    In article <107ojb9$1e84t$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin...
    https://pastebin.com/raw/CYZ78gVj

    No need, I'm afraid.

    You don't like proxy collectors? Or you think mine is shit?

    Sorry, I'm just not sure you're a useful source of code like
    this. It's subtle and requires a lot of in-depth understanding
    of very thorny issues that it doesn't strike me you have a good
    handle on.

    - Dan C.


    Fwiw, some of my math is taking notice. An example:

    https://paulbourke.net/fractals/multijulia/

    Also, I made it into the cover of the AMS calendar. They even put my
    work on their webpage:

    https://www.ams.org/publicoutreach/math-imagery/math-imagery

    Notice my name?

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Tue Aug 19 08:56:50 2025
    In article <108067e$3ccku$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:39 PM, Dan Cross wrote:
    In article <10802os$3bdl8$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:25 PM, Dan Cross wrote:
    In article <107ojb9$1e84t$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin...
    https://pastebin.com/raw/CYZ78gVj

    No need, I'm afraid.

    You don't like proxy collectors? Or you think mine is shit?

    Sorry, I'm just not sure you're a useful source of code like
    this. It's subtle and requires a lot of in-depth understanding
    of very thorny issues that it doesn't strike me you have a good
    handle on.

    Fwiw, some of my math is taking notice. An example:

    https://paulbourke.net/fractals/multijulia/

    Also, I made it into the cover of the AMS calendar. They even put my
    work on their webpage:

    https://www.ams.org/publicoutreach/math-imagery/math-imagery

    Notice my name?

    No, I don't. Using their integrated search feature for the
    string, "Thomasson" only turns up a few links to an actual
    mathematician working on graph theory.

    In fact, most of the links you are posting don't seem to involve
    you at all. The only one that actually seems to refer to you is
    a short note on Vyukov's page; I have no idea why that's there.
    It seems rather old.

    Bluntly, I'm really not all that interested.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 09:09:52 2025
    On 8/18/2025 3:56 PM, Dan Cross wrote:
    In article <108067e$3ccku$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:39 PM, Dan Cross wrote:
    In article <10802os$3bdl8$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:25 PM, Dan Cross wrote:
    In article <107ojb9$1e84t$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:

    When you get bored, give my lock-free proxy collector a spin...
    https://pastebin.com/raw/CYZ78gVj

    No need, I'm afraid.

    You don't like proxy collectors? Or you think mine is shit?

    Sorry, I'm just not sure you're a useful source of code like
    this. It's subtle and requires a lot of in-depth understanding
    of very thorny issues that it doesn't strike me you have a good
    handle on.

    Fwiw, some of my math is taking notice. An example:

    https://paulbourke.net/fractals/multijulia/

    Also, I made it into the cover of the AMS calendar. They even put my
    work on their webpage:

    https://www.ams.org/publicoutreach/math-imagery/math-imagery

    Notice my name?

    No, I don't.

    Look again. Notice the graphic on the webpage:

    https://i.ibb.co/23gKYK0w/image.png

    They give me credit for my field line render called iWire.


    Using their integrated search feature for the
    string, "Thomasson" only turns up a few links to an actual
    mathematician working on graph theory.

    I did not write a paper for them. But showed them some of my vector
    field work, and they said wow!


    In fact, most of the links you are posting don't seem to involve
    you at all. The only one that actually seems to refer to you is
    a short note on Vyukov's page; I have no idea why that's there.
    It seems rather old.

    Well, yeah, its from my old work. Vyukov and I are friends from way back
    on c.p.t. I helped him find bugs in his Relacy race detector, and we
    discussed many interesting things, way back 20+ years ago.


    Bluntly, I'm really not all that interested.

    I made the cover of the 2025 AMS Calendar of Mathematical Imagery:

    https://www.facebook.com/photo/?fbid=1218640825961580&set=pcb.1218640912628238

    https://i.ibb.co/TqrhBrjk/image.png

    Pretty cool!

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 09:11:55 2025
    On 8/18/2025 1:44 PM, Dan Cross wrote:
    In article <108031c$3bdl8$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 1:26 PM, Dan Cross wrote:
    In article <107ojfk$1e84t$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/13/2025 4:41 AM, Dan Cross wrote:
    In article <107dkai$2rg26$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 8:08 PM, Dan Cross wrote:
    In article <10781l0$1eamj$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/9/2025 9:08 AM, Dan Cross wrote:
    In article <10775om$17ms4$1@raubtier-asyl.eternal-september.org>, >>>>>>>>> Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.08.2025 um 11:17 schrieb Dan Cross:

    People have written code that tries to take a lock, and if that >>>>>>>>>>> fails, does something else, for decades. The idea is neither >>>>>>>>>>> new, nor terribly interesting. Sorry.

    I think this pattern is extremely rare because the task that needs to
    be done elsewhere must be able to be omitted completely if necessary,
    and if not, it must be short enough that it doesn't interfere with >>>>>>>>>> waiting for the mutex.

    Yeah. That's why I mentioned concentrating on the specific
    critical section the mutex is protecting, not the locking
    protocol. Where this has any utility at all, it's in places >>>>>>>>> where the "something else" is well-known, which implies it being >>>>>>>>> a function of the critsec. It's going to be things like, "if I >>>>>>>>> fail to acquire the scheduler lock, then increment this per-core >>>>>>>>> atomic counter that's measuring contention...." sort of thing. >>>>>>>>
    More grasping at straws and/or trying to breath underwater without scuba
    gear... The other work is very specialized. It can be as simple as >>>>>>>> processing a per-thread local queue or something. Just something that >>>>>>>> can act like a backoff that does real work in a case of contention. Sigh.

    That's the sort of thing where you cannot know what's on that
    "per-thread local queue" that makes your scheme fail.

    Well, that per-thread local queue can be for organization, maintenance, >>>>>> sending the results to a "logic" thread, ect. Think of a server io >>>>>> thread that takes the io completions and organizes them into local >>>>>> queues. These io threads do not call into user logic, or processing wrt >>>>>> say, parsing HTTP, or some protocol. So, some work that can be used >>>>>> after a try_lock fails can be to push the local queues to the logic threads.

    This, yet again, seems to be where you don't understand the
    issue at stake here.

    You can _probably_ find _any number of things_ that you can do
    while looping over `try_lock`. I don't care about the specific
    examples: they obviously exist.

    But what you _cannot_ do, and what makes this sort of scheme
    fail, is know that _all_ such work is safe. Unless you can wave
    a magic wand and solve the halting problem, you won't be able to
    know that some jerk won't send you "work" that amounts to a
    non-terminating infinite loop. You won't be able to know that
    some other jerk hasn't sent you "work" that causes you to
    deadlock trying to take a mutex you already hold. Etc.

    If you _ever_ open yourself up to accepting "work" on some kind
    of queue, where the types of all work that can possibly be sent
    to you is not known in advance _in some way that can be enforced
    in code_, then your scheme fails. And if you do have some way
    to enforce those constraints, then the scheme is neither novel
    nor particularly interesting.

    If your lock is contended, you could just sleep on it, and let
    the kernel schedule something else instead. There's no value to >>>>>>> keeping your thread "hot" unless you've got a profile showing
    that it's an issue.

    But why sleep when the thread can do some real work?

    Because the OS (or even a user-level thread scheduler, or
    language runtime, or whatever) can find work to usefully do on
    that CPU, _without_ the downsides mentioned above. So you lose
    nothing but gain correctness and stability.

    Argh. Grasping
    again. Feels like I am drowning. Shit! ;^o

    Perhaps stop doing that, then. It's clear you are not going to
    find a way to make whatever partially developed idea you have
    work.

    It should be okay if the other work is okay with it?

    Again: you have no way of knowing that "the other work is okay
    with it".

    Sure you can in highly controlled scenarios? A programmer can say, this
    type of work can be done in this condition because the programmer knows
    what the work consists of... I listed a few of them before. I am not
    going for some sort of general case type of thing.


    It's ok to be wrong. It's less ok to keep trying to convince
    others that you are right.

    It just seems to be okay, well, after a try_lock fails try to do
    something that is _compatible_ instead of something like an adaptive
    mutex? Shit. Yikes!

    There I go again. Sorry.

    [...]

    Please stop.

    It sure seems like it cannot be 100% wrong all the time. Having trouble
    seeing that.

    It's already in the above quoted text. The relevant section is
    here:

    |You can _probably_ find _any number of things_ that you can do
    |while looping over `try_lock`. I don't care about the specific
    |examples: they obviously exist.
    |
    |But what you _cannot_ do, and what makes this sort of scheme
    |fail, is know that _all_ such work is safe. Unless you can wave
    |a magic wand and solve the halting problem, you won't be able to
    |know that some jerk won't send you "work" that amounts to a
    |non-terminating infinite loop. You won't be able to know that
    |some other jerk hasn't sent you "work" that causes you to
    |deadlock trying to take a mutex you already hold. Etc.
    |
    |If you _ever_ open yourself up to accepting "work" on some kind
    |of queue, where the types of all work that can possibly be sent
    |to you is not known in advance _in some way that can be enforced
    |in code_, then your scheme fails. And if you do have some way
    |to enforce those constraints, then the scheme is neither novel
    |nor particularly interesting.

    Just saying, "yay! I can do something while spinning on a lock!"
    is so vaccuously obvious that it's simply uninteresting; people
    have done such things for many, many years. Your error is in
    trying to extrapolate that to "other" work.

    - Dan C.


    It was fun when Sun gave me a T2000 SunFire server wrt to their
    CoolThreads contest.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 09:20:36 2025
    On 8/18/2025 1:44 PM, Dan Cross wrote:
    [...]

    I remember a really old Intel white paper mentioned my old AppCore work.
    But, I cannot find it. Sigh.



    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Tue Aug 19 09:44:22 2025
    In article <1080bs0$3dqgt$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 3:56 PM, Dan Cross wrote:
    In article <108067e$3ccku$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    Notice my name?

    No, I don't.

    Look again. Notice the graphic on the webpage:

    https://i.ibb.co/23gKYK0w/image.png

    They give me credit for my field line render called iWire.

    Sorry, I'm just not that interested.

    I don't really see what any of this has to do with C++.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Tue Aug 19 09:55:35 2025
    On 8/18/2025 4:44 PM, Dan Cross wrote:
    In article <1080bs0$3dqgt$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 3:56 PM, Dan Cross wrote:
    In article <108067e$3ccku$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    Notice my name?

    No, I don't.

    Look again. Notice the graphic on the webpage:

    https://i.ibb.co/23gKYK0w/image.png

    They give me credit for my field line render called iWire.

    Sorry, I'm just not that interested.

    I don't really see what any of this has to do with C++.

    The only thing is I used C++ to implement iWire. ;^) Anyway, I have a
    lot of experience with lock/wait/obstruction-free algos. A fun part was helping Dmitriy find bugs in his Relacy project when he first created it
    back on c.p.t.

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Dan Cross@3:633/280.2 to All on Tue Aug 19 09:57:15 2025
    In article <1080ehn$3ek5d$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 4:44 PM, Dan Cross wrote:
    In article <1080bs0$3dqgt$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 3:56 PM, Dan Cross wrote:
    In article <108067e$3ccku$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    Notice my name?

    No, I don't.

    Look again. Notice the graphic on the webpage:

    https://i.ibb.co/23gKYK0w/image.png

    They give me credit for my field line render called iWire.

    Sorry, I'm just not that interested.

    I don't really see what any of this has to do with C++.

    The only thing is I used C++ to implement iWire. ;^) Anyway, I have a
    lot of experience with lock/wait/obstruction-free algos. A fun part was >helping Dmitriy find bugs in his Relacy project when he first created it >back on c.p.t.

    Like I said, I'm not really interested. And besides, this is
    comp.lang.c++; none of this feels at all relevant.

    - Dan C.


    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: PANIX Public Access Internet and UNIX, NYC (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Wed Aug 20 06:25:20 2025
    On 8/18/2025 4:57 PM, Dan Cross wrote:
    In article <1080ehn$3ek5d$1@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 4:44 PM, Dan Cross wrote:
    In article <1080bs0$3dqgt$3@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    On 8/18/2025 3:56 PM, Dan Cross wrote:
    In article <108067e$3ccku$2@dont-email.me>,
    Chris M. Thomasson <chris.m.thomasson.1@gmail.com> wrote:
    Notice my name?

    No, I don't.

    Look again. Notice the graphic on the webpage:

    https://i.ibb.co/23gKYK0w/image.png

    They give me credit for my field line render called iWire.

    Sorry, I'm just not that interested.

    I don't really see what any of this has to do with C++.

    The only thing is I used C++ to implement iWire. ;^) Anyway, I have a
    lot of experience with lock/wait/obstruction-free algos. A fun part was
    helping Dmitriy find bugs in his Relacy project when he first created it
    back on c.p.t.

    Like I said, I'm not really interested. And besides, this is
    comp.lang.c++; none of this feels at all relevant.

    Fair enough. Fwiw, my proxy collector is pretty interesting, well, to me anyway, and works fine. I need to find my impl of it in Relacy. Who
    knows, you might like it. If you are ever _really_ bored, I mean no
    books to read, nothing on tv, nothing to code, nobody to talk to, well,
    give it a go sometime. If you ever do, please tell be about your
    experience. Thanks. :^)

    --- MBSE BBS v1.1.2 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)