- neoGFX: Transitions (applying an easing function to a widget property) - 1 Update
- cmsg cancel <ptf22s$1a1$1@dont-email.me> - 1 Update
- constexpr issues - 1 Update
- experimental multi-mutex algorithm... - 4 Updates
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Nov 27 11:27PM \o/ Just implemented transitions; video is of applying an easing function to a widget property (widget position) .. https://www.youtube.com/watch?v=7UZTGqskPuI #cpp #coding #gamedev /Flibble -- "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Bryne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
Elephant Man <conanospamic@gmail.com>: Nov 27 09:12PM Article d'annulation posté via Nemo. |
"Öö Tiib" <ootiib@hot.ee>: Nov 27 08:28AM -0800 > "g++ -std=c++17 t.cpp" works well, I forgot the standard option for g++. > But the standard I am after is c++11. "g++ -std=c++11 t.cpp" causes the > same linker error! I can not understand why. If you want to use C++11 then you should not use C++17 features. You have to define the Token::Pi in C++11. Adding that to end of your file ...: constexpr Str Token::Pi; ... will make it to compilöe with -std=c++11 too. If you want to learn to use constexpr then I would suggest to forget C++11. The constexpr as of C++11 is rather limited and crippled, especially about functions. There it feels like a hack to simplify some of most obscure template metaprogramming tricks and for some performance optimizations. The constexpr of C++17 on the other hand feels like a way to mark pure functions (in functional programming sense) with keyword constexpr. Preferring pureness is quite good programming idiom in general, about like preferring immutability is good programming idiom in general. |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Nov 26 09:59PM -0800 On 11/25/2018 10:19 PM, Chris M. Thomasson wrote: > pointers into a table of locks. A thread can create a little array of > hashed pointers, sort them, remove duplicates, then take all of the > locks in the table. The sorting and uniqueness factor prevents deadlock. [...] Hey now, this crude example code actually uses threads. ;^) Deadlock free hashed address based locking, dead simple wrt a locking hierarchy. It can be improved upon for sure. I am calling it the Multex. Also, keep in mind that the locks are different than the memory pointed to by the hashed pointers. So, this can be used to simulate atomic operations on a system that only has semaphores. It easily solves the Dining Philosophers problem. The main and ct_thread functions show an example on how to use it: ____________________________ /* The Multex, simple deadlock free locking abstraction By Chris M. Thomasson ____________________________________________________________*/ #include <iostream> #include <functional> #include <algorithm> #include <mutex> #include <thread> #include <cassert> #include <cstddef> #include <cstdint> #include <vector> #define THREADS 7 #define N 123456 // Allows one to lock multiple addresses // at once, and never hit a deadlock. // It is an experiment. namespace ct_multex { // A table of locks struct mutex_table { std::vector<std::mutex> m_locks; mutex_table(std::size_t size) : m_locks(size) { assert(size > 0); } // totally contrived simple hash... std::size_t hash(void const* ptr) { std::uintptr_t ptr_uint = (std::uintptr_t)ptr; return (std::size_t)(((ptr_uint << 9) * 103) % m_locks.size()); } }; // A threads local indices into a table of locks struct local_locks { std::vector<std::size_t> m_lock_idxs; mutex_table& m_mtx_tbl; local_locks(mutex_table& mtx_tbl) : m_lock_idxs(), m_mtx_tbl(mtx_tbl) {} // Add an address to be locked void push_ptr(void const* ptr) { std::size_t idx = m_mtx_tbl.hash(ptr); m_lock_idxs.push_back(idx); } // Deadlock free, baby! ;^) void ensure_locking_order() { // sort and remove duplicates... std::sort(m_lock_idxs.begin(), m_lock_idxs.end()); m_lock_idxs.erase(std::unique(m_lock_idxs.begin(), m_lock_idxs.end()), m_lock_idxs.end()); } // Take all of the locks void lock() { // there can be a flag to minimize this... ensure_locking_order(); std::size_t n = m_lock_idxs.size(); for (std::size_t i = 0; i < n; ++i) { m_mtx_tbl.m_locks[m_lock_idxs[i]].lock(); } } // Unlock everything void unlock() { std::size_t n = m_lock_idxs.size(); for (std::size_t i = 0; i < n; ++i) { m_mtx_tbl.m_locks[m_lock_idxs[n - i - 1]].unlock(); } } }; // RAII scoped lock: Allows a thread to actualy take the locks // It locks a threads local lock indices struct scoped_lock { local_locks& m_locks; scoped_lock(local_locks& locks) : m_locks(locks) { m_locks.lock(); } ~scoped_lock() throw() { m_locks.unlock(); } }; } // Test program... //______________________________________ // Shared data struct ct_shared { ct_multex::mutex_table& m_multex; ct_shared(ct_multex::mutex_table& multex) : m_multex(multex), data_0(1), data_1(2), data_2(3), data_3(4) { } unsigned long data_0; unsigned long data_1; unsigned long data_2; unsigned long data_3; }; // a thread void ct_thread(ct_shared& shared) { // Create our local locks ct_multex::local_locks locks(shared.m_multex); // Add some addresses locks.push_ptr(&shared.data_2); locks.push_ptr(&shared.data_0); // Do some work for (unsigned long i = 0; i < N / 2; ++i) { { ct_multex::scoped_lock slock(locks); // locked for data_0 and data_2 shared.data_0 += i; shared.data_2 += i; } std::this_thread::yield(); { ct_multex::scoped_lock slock(locks); // locked for data_0 and data_2 shared.data_0 -= i; std::this_thread::yield(); // for fun... shared.data_2 -= i; } } // Add some other addresses locks.push_ptr(&shared.data_1); locks.push_ptr(&shared.data_3); // Do some more work... for (unsigned long i = 0; i < N / 2; ++i) { { ct_multex::scoped_lock slock(locks); // locked for data_0, data_1, data_2 and data_3 shared.data_0 += i; std::this_thread::yield(); // for fun... shared.data_1 += i; shared.data_2 += i; shared.data_3 += i; } std::this_thread::yield(); { ct_multex::scoped_lock slock(locks); // locked for data_0, data_1, data_2 and data_3 shared.data_0 -= i; shared.data_1 -= i; shared.data_2 -= i; std::this_thread::yield(); // for fun... shared.data_3 -= i; } } } int main(void) { { // Our mutex table ct_multex::mutex_table multex_tbl(42); // Our shared data ct_shared shared(multex_tbl); // Launch... { std::thread threads[THREADS]; // Create threads... for (unsigned long i = 0; i < THREADS; ++i) { threads[i] = std::thread(ct_thread, std::ref(shared)); } std::cout << "processing...\n\n"; std::cout.flush(); // Join threads... for (unsigned long i = 0; i < THREADS; ++i) { threads[i].join(); } } // Verify the shared data... std::cout << "shared.data_0 = " << shared.data_0 << "\n"; std::cout << "shared.data_1 = " << shared.data_1 << "\n"; std::cout << "shared.data_2 = " << shared.data_2 << "\n"; std::cout << "shared.data_3 = " << shared.data_3 << "\n"; assert(shared.data_0 == 1); assert(shared.data_1 == 2); assert(shared.data_2 == 3); assert(shared.data_3 == 4); } std::cout << "\n\nfin!\n\n"; return 0; } ____________________________ Can you get it to run? thanks. |
Melzzzzz <Melzzzzz@zzzzz.com>: Nov 27 07:24AM > Can you get it to run? > thanks. ~/News >>> g++ -std=c++17 -O3 -march=native -pthread mmtex.cpp -o mmtex 2> errors ~/News >>> vim errors ~/News >>> ./mmtex processing... shared.data_0 = 1 shared.data_1 = 2 shared.data_2 = 3 shared.data_3 = 4 fin! -- press any key to continue or any other to quit... |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Nov 26 11:25PM -0800 On 11/26/2018 9:59 PM, Chris M. Thomasson wrote: > // It is an experiment. > namespace ct_multex > { [...] > m_mtx_tbl.m_locks[m_lock_idxs[i]].lock(); > } > } [...] Fwiw, there is another way to take the locks, using a try_lock and backoff scheme, something like: _____________________________ // Take all of the locks void lock() // optimistic { // there can be a flag to minimize this... ensure_locking_order(); std::size_t n = m_lock_idxs.size(); for (std::size_t i = 0; i < n; ++i) { if (! m_mtx_tbl.m_locks[m_lock_idxs[i]].try_lock()) { // Unlock our previous addresses... for (std::size_t u = 0; u < i; ++u) { m_mtx_tbl.m_locks[m_lock_idxs[i - u - 1]].unlock(); } // backoff algorithm, or whatever... std::this_thread::yield(); // Try again... i = SIZE_MAX; continue; } } } _____________________________ Remember to include <climits> for SIZE_MAX. The try_lock version does not even need to be sorted, just unique. |
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Nov 27 12:56AM -0800 On 11/26/2018 11:24 PM, Melzzzzz wrote: > shared.data_2 = 3 > shared.data_3 = 4 > fin! Thanks for trying it out Melzzzzz. :^) The basic algorithm can be useful for many things involving locking. There is another more "optimistic" version I am tinkering around with that can be used for n-address based software transactional memory. One note, this is not recursive! |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment