- Blocking queue - 17 Updates
- About SC and TSO and RMO hardware memory models.. - 1 Update
- "The State of C++ on Windows" - 1 Update
- OT: Github - 1 Update
"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>: Feb 03 09:01PM -0800 On 2/3/2019 1:52 PM, Chris M. Thomasson wrote: > semaphore has a mutex and condvar. You have two of them plus another > mutex. That is: > 3 mutexes and 2 condvars for a single queue? Still need to examine it more carefully, but the following function is a race-condition if it is concurrently called by more than one thread: bool empty() { return m_count == 0; } You are allowing reads and writes to hit m_count at the same time in this call. |
"Öö Tiib" <ootiib@hot.ee>: Feb 04 01:32AM -0800 > My multi-threaded blocking queue implementation: https://blog.vorbrodt.me/?p=409 If you want to make std::queue pop blocking then one mutex and one condition variable should be fine. Something like that: #include <queue> #include <thread> #include <mutex> #include <condition_variable> template <typename T> class Queue { public: T pop() { std::unique_lock<std::mutex> mlock(mutex_); while (queue_.empty()) { cond_.wait(mlock); } auto item = queue_.front(); queue_.pop(); return item; } void push(T item) { std::unique_lock<std::mutex> mlock(mutex_); queue_.push(item); mlock.unlock(); cond_.notify_one(); } private: std::queue<T> queue_; std::mutex mutex_; std::condition_variable cond_; }; So blocking pop implemented, without need for boost or anything. Now if you have some sort of improvement to it for some special case then describe the case and show benefits of your implementation with benchmarks. |
mvorbrodt@gmail.com: Feb 04 05:08AM -0800 On Monday, February 4, 2019 at 4:32:34 AM UTC-5, Öö Tiib wrote: > Now if you have some sort of improvement to it for some > special case then describe the case and show benefits of > your implementation with benchmarks. your implementation grows indefinitely on push(). mine will eventually block when the queue fills up. |
mvorbrodt@gmail.com: Feb 04 05:09AM -0800 On Monday, February 4, 2019 at 12:01:41 AM UTC-5, Chris M. Thomasson wrote: > } > You are allowing reads and writes to hit m_count at the same time in > this call. you are right. I modified the code to lock around the check for empty. |
mvorbrodt@gmail.com: Feb 04 05:12AM -0800 On Sunday, February 3, 2019 at 4:52:41 PM UTC-5, Chris M. Thomasson wrote: > semaphore has a mutex and condvar. You have two of them plus another > mutex. That is: > 3 mutexes and 2 condvars for a single queue? semaphores for clarity of implementation and easy counting of empty and full slots. |
"Öö Tiib" <ootiib@hot.ee>: Feb 04 06:19AM -0800 > > special case then describe the case and show benefits of > > your implementation with benchmarks. > your implementation grows indefinitely on push(). mine will eventually block when the queue fills up. Then one more conditional variable is needed for blocking push, still no need for boost or anything. |
Bonita Montero <Bonita.Montero@gmail.com>: Feb 04 04:26PM +0100 > your implementation grows indefinitely on push(). mine will eventually block when the queue fills up. When do you think a queue with limited capacity is necessary? I think that's rather exotic. |
Robert Wessel <robertwessel2@yahoo.com>: Feb 04 09:59AM -0600 On Mon, 4 Feb 2019 16:26:33 +0100, Bonita Montero >> your implementation grows indefinitely on push(). mine will eventually block when the queue fills up. >When do you think a queue with limited capacity is necessary? >I think that's rather exotic. Limited queue growth is not an uncommon requirement. In cases where you have one set of processes generating work, and another performing it, you often want to keep those decoupled and running independently to make maximum use of resources, but you don't want unlimited numbers of work items filling memory. Usually, though, I've done that by placing an separate limit on the queue depth. You can often avoid the blocking entirely if you can have the generating process execute the work unit directly if the queue is full. |
Bonita Montero <Bonita.Montero@gmail.com>: Feb 04 06:12PM +0100 > it, you often want to keep those decoupled and running independently > to make maximum use of resources, but you don't want unlimited numbers > of work items filling memory. Why not? Memory is cheap. > queue depth. You can often avoid the blocking entirely if you can > have the generating process execute the work unit directly if the > queue is full. ... and thereby block further processing in the producer. Very smart! |
Bonita Montero <Bonita.Montero@gmail.com>: Feb 04 06:17PM +0100 > Why not? Memory is cheap. To be more precise: The data-structures which are handed through the queue to the consumer are in memory anyway and are usually much larger than a simple link-node in the queue. |
David Brown <david.brown@hesbynett.no>: Feb 04 08:40PM +0100 On 04/02/2019 18:17, Bonita Montero wrote: > To be more precise: The data-structures which are handed through the > queue to the consumer are in memory anyway and are usually much larger > than a simple link-node in the queue. That means that the producer needs to use a lot more memory to make these data structures - it can make sense to limit that by blocking the producer. And memory is not always cheap. Unlimited memory is almost always very expensive. (That does not mean having a specific limit to the size of the queue is the best solution - it might be, but there may be other solutions.) |
mvorbrodt@gmail.com: Feb 04 11:58AM -0800 On Monday, February 4, 2019 at 10:26:44 AM UTC-5, Bonita Montero wrote: > > your implementation grows indefinitely on push(). mine will eventually block when the queue fills up. > When do you think a queue with limited capacity is necessary? > I think that's rather exotic. it's used for throttling. sometimes you don't want it to grow indefinitely. |
"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>: Feb 04 01:46PM -0800 >> mutex. That is: >> 3 mutexes and 2 condvars for a single queue? > semaphores for clarity of implementation and easy counting of empty and full slots. Fair enough! :^) |
"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>: Feb 04 01:59PM -0800 On 2/4/2019 1:46 PM, Chris M. Thomasson wrote: >> semaphores for clarity of implementation and easy counting of empty >> and full slots. > Fair enough! :^) Btw, there is a faster semaphore out there that can be implemented in C++11: https://groups.google.com/d/topic/comp.lang.c++/60IpFwqbtu8/discussion (read all if interested...) Here is a direct link to a crude sample implementation: http://pastebin.com/raw/Q7p6e7Xc (no ads, raw text...) Imvvho, this semaphore is nice, notice how it can skip waiting on a mutex/condvar based semaphore? |
"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>: Feb 04 02:14PM -0800 >> You are allowing reads and writes to hit m_count at the same time in >> this call. > you are right. I modified the code to lock around the check for empty. That's fine. Now, if this empty check could be relaxed to a standard form of "racy", then one could define m_count as a std::atomic type, and read and write it with std::memory_order_relaxed. As is, it would be fine using your current code. However, the data returned is dubious because the mutex m_cs was not locked where you mutate m_count. If empty is called a lot, then this type of racy check might be perfectly fine. Keep in mind that there is a difference between racing using atomic types vs raw variables. Fwiw, here is a massive race condition, yet it is 100% perfectly standard compliant: https://groups.google.com/d/topic/comp.lang.c++/7u_rLgQe86k/discussion ;^) |
"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>: Feb 04 02:21PM -0800 >> When do you think a queue with limited capacity is necessary? >> I think that's rather exotic. > it's used for throttling. sometimes you don't want it to grow indefinitely. Big time! Fwiw, if interested, check out my simple mutation to a very nice _bounded_ FIFO queue: https://groups.google.com/d/topic/lock-free/acjQ3-89abE/discussion (read all if interested, please read all...) |
"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>: Feb 04 02:39PM -0800 On 2/4/2019 11:40 AM, David Brown wrote: > That means that the producer needs to use a lot more memory to make > these data structures - it can make sense to limit that by blocking the > producer. Right. Or even give a flag to the producer such that it can possibly do "other" work instead of wait right then and there. It can do some other work, then check back at the queue to see if it is still in the full state. Like a continuation sparked by a queue full condition. A producer can do other work if possible, and check the queue again. A producer can even queue work locally to a per-thread structure on a bounded full condition, then, when the queue gets consumed a bit, well, it can send all the local work in a single atomic shot. > expensive. > (That does not mean having a specific limit to the size of the queue is > the best solution - it might be, but there may be other solutions.) Fwiw, bounded queues are fairly normal, in my experience at least. |
Horizon68 <horizon@horizon.com>: Feb 04 01:19PM -0800 Hello.. About SC and TSO and RMO hardware memory models.. I have just read the following webpage about the performance difference between: SC and TSO and RMO hardware memory models I think TSO is better, it is just around 3% ~ 6% less performance than RMO and it is a simpler programming model than RMO. So i think ARM must support TSO to be compatible with x86 that is TSO. Read more here to notice it: https://infoscience.epfl.ch/record/201695/files/CS471_proj_slides_Tao_Marc_2011_1222_1.pdf About memory models and sequential consistency: As you have noticed i am working with x86 architecture.. Even though x86 gives up on sequential consistency, it's among the most well-behaved architectures in terms of the crazy behaviors it allows. Most other architectures implement even weaker memory models. ARM memory model is notoriously underspecified, but is essentially a form of weak ordering, which provides very few guarantees. Weak ordering allows almost any operation to be reordered, which enables a variety of hardware optimizations but is also a nightmare to program at the lowest levels. Read more here: https://homes.cs.washington.edu/~bornholt/post/memory-models.html Memory Models: x86 is TSO, TSO is Good Essentially, the conclusion is that x86 in practice implements the old SPARC TSO memory model. The big take-away from the talk for me is that it confirms the observation made may times before that SPARC TSO seems to be the optimal memory model. It is sufficiently understandable that programmers can write correct code without having barriers everywhere. It is sufficiently weak that you can build fast hardware implementation that can scale to big machines. Read more here: https://jakob.engbloms.se/archives/1435 Thank you, Amine Moulay Ramdane. |
Cholo Lennon <chololennon@hotmail.com>: Feb 04 05:34PM -0300 On 2/3/19 7:55 AM, Alf P. Steinbach wrote: > "With C++/WinRT, you can author and consume Windows Runtime APIs using > any standards-compliant C++17 compiler." > Has anyone tried to use MinGW g++? Not me, but it would be a good exercise in order to test the Microsoft marketing :-) -- Cholo Lennon Bs.As. ARG |
woodbrian77@gmail.com: Feb 03 08:31PM -0800 > I'm wondering if the next problem after this will be that > it's building on Windows 10 and my makefile refers to Windows > 7 libs. At least the Appveyor gui isn't totally lame. I decided to use an appveyor.yml file rather than the gui. My appveyor.yml is based on the one in Premake's repo: os: Visual Studio 2017 platform: - Win32 - x64 configuration: - Debug - Release before_build: - cmd: git clean -ffxd build_script: - cmd: call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" - cmd: nmake -f makefile.vs MSDEV=vs2017 windows PLATFORM=%PLATFORM% CONFIG=%CONFIGURATION% -------------------------------------------------------- But something about it or the makefile: https://github.com/Ebenezer-group/onwards/blob/master/makefile.vs isn't working right. And I'm not sure if I've run out of something with my free Appveyor account, but previously I could get some info about what was failing. After approximately 50 builds, I'm no longer able to figure out how to get more info, but it still says it failed. Anyway, I'm thankful for this yml file. It's not as crazy as the other yml files I've seen. It's almost reasonable. Tia. Brian Ebenezer Enterprises - "For G-d so loved the world, that He gave His only Son, that whoever believes in Him should not perish but have eternal life." John 3:16 http://webEbenezer.net |
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