C++ (Qt)#include <atomic>#include <cstring>#include <iostream>#include <thread> struct Buffer{ enum { MaxCount = 0x0004 }; struct Packet { std::atomic< bool > m_is_exists; Packet () : m_is_exists() {} }; std::atomic< uint32_t > m_write_head; std::atomic< uint32_t > m_read_head; Packet m_packet[ MaxCount ]; void push () { uint32_t pos = ( m_write_head++ ) % MaxCount; while( m_packet[ pos ].m_is_exists ); m_packet[ pos ].m_is_exists = true; } void pop () { uint32_t pos = ( m_read_head++ ) % MaxCount; while ( !m_packet[ pos ].m_is_exists ); m_packet[ pos ].m_is_exists = false; }}; static Buffer global_buffer;static std::atomic< uint32_t > write_count;static std::atomic< uint32_t > read_count; void pushValue (){ global_buffer.push(); ++write_count;} void popValue (){ global_buffer.pop(); ++read_count;} void write ( size_t count ){ for ( size_t i = 0; i < count; ++i ) pushValue();} void read ( size_t count ){ for ( size_t i = 0; i < count; ++i ) popValue();} int main ( int /*argc*/, char */*argv*/[] ){ std::thread first_writer( write, 10000000 ); std::thread second_writer( write, 20000000 ); std::thread reader( read, 30000000 ); first_writer.join(); second_writer.join(); reader.join(); std::cout << "Write count: " << write_count.load() << std::endl; std::cout << "Read count: " << read_count.load() << std::endl; return 0;}
C++ (Qt)struct Buffer{ enum { MaxCount = 0x0004 }; struct Packet { std::atomic< bool > m_is_exists; Packet () : m_is_exists() {} }; std::atomic< uint32_t > m_write_head; std::atomic< uint32_t > m_read_head; Packet m_packet[ MaxCount ]; void push () { uint32_t pos = ( m_write_head++ ) % MaxCount; bool expected = false; while( !m_packet[ pos ].m_is_exists.compare_exchange_weak( expected, true ) ); } void pop () { uint32_t pos = ( m_read_head++ ) % MaxCount; bool expected = true; while( !m_packet[ pos ].m_is_exists.compare_exchange_weak( expected, false ) ); }};
C++ (Qt)#include <atomic>#include <cassert>#include <cstring>#include <iostream>#include <thread> typedef int Data; struct Buffer{ enum { MaxCount = 0x0004 }; struct Packet { Data m_value; std::atomic< bool > m_is_exists; Packet () : m_value(), m_is_exists() {} }; std::atomic< uint32_t > m_write_head; std::atomic< uint32_t > m_read_head; std::atomic< uint32_t > m_count; Packet m_packet[ MaxCount ]; bool push ( const Data & value ) { if ( m_count >= MaxCount ) return false; uint32_t pos = ( m_write_head++ ) % MaxCount; bool expected = false; while( !m_packet[ pos ].m_is_exists.compare_exchange_weak( expected, true ) ); m_packet[ pos ].m_value = value; m_packet[ pos ].m_is_exists = true; ++m_count; return true; } bool pop ( Data & value ) { if ( m_count == 0 ) return false; uint32_t pos = ( m_read_head++ ) % MaxCount; bool expected = true; while( !m_packet[ pos ].m_is_exists.compare_exchange_weak( expected, false ) ); value = m_packet[ pos ].m_value; m_packet[ pos ].m_value = Data(); m_packet[ pos ].m_is_exists = false; --m_count; return true; }}; static Buffer global_buffer;static std::atomic< uint32_t > write_count;static std::atomic< uint32_t > read_count; void pushValue (){ Data value = 1; while( !global_buffer.push( value ) ); ++write_count;} void popValue (){ Data value; while( !global_buffer.pop( value ) ); assert( value == 1 ); ++read_count;} void write ( size_t count ){ for ( size_t i = 0; i < count; ++i ) pushValue();} void read ( size_t count ){ for ( size_t i = 0; i < count; ++i ) popValue();} int main ( int /*argc*/, char */*argv*/[] ){ std::thread first_writer( write, 10000000 ); std::thread second_writer( write, 20000000 ); std::thread reader( read, 30000000 ); first_writer.join(); second_writer.join(); reader.join(); std::cout << "Write count: " << write_count.load() << std::endl; std::cout << "Read count: " << read_count.load() << std::endl; return 0;}
C++ (Qt) void push () { uint32_t pos = ( m_write_head++ ) % MaxCount; while( m_packet[ pos ].m_is_exists ); // <<<<<< здесь нитка может переключиться, а когда она получит управление обратно, уже не известно что будет в m_is_exists m_packet[ pos ].m_is_exists = true; }
C++ (Qt)// <<<<<< здесь нитка может переключиться, а когда она получит управление обратно, уже не известно что будет в m_is_exists
C++ (Qt)enum { flag_busy = 1, // есть чтение или запись flag_data = 2, // есть данные}; void Buffer::push( int data ){ uint32_t pos = ( m_write_head++ ) % MaxCount; // захватываем cвободную ячейку while (true) { int expected = 0; if (m_packet[pos].m_is_exists.compare_exchange_weak(expected, flag_busy)) break; // yield ? abortFlag ? } // пишем данные m_packet[pos].m_data = data; // освобождаем ячейку ставя ей флаг "есть данные" m_packet[pos].m_exists = flag_data;} int Buffer::pop( void ){ uint32_t pos = (m_read_head++) % MaxCount; // захватываем ячейку c данными while (true) { int expected = flag_data; if (m_packet[pos].m_is_exists.compare_exchange_weak(expected, flag_busy)) break; // yield ? abortFlag ? } // читаем данные int data = m_packet[pos].m_data; // освобождаем ячейку ставя ей флаг 0 (свободна) m_packet[pos].m_exists = 0; return data;}
C++ (Qt)struct Buffer{ enum { MaxCount = 0x0400 }; enum class Status : uint8_t { Empty, Proceed, Complete }; struct Packet { Data m_value; std::atomic< Status > m_status; Packet () : m_value(), m_status() {} }; std::atomic< uint32_t > m_write_head; std::atomic< uint32_t > m_read_head; std::atomic< uint32_t > m_count; Packet m_packet[ MaxCount ]; bool push ( const Data & value ) { if ( m_count >= MaxCount ) return false; uint32_t pos = ( m_write_head++ ) % MaxCount; Status expected = Status::Empty; while( !m_packet[ pos ].m_status.compare_exchange_weak( expected, Status::Proceed ) ) expected = Status::Empty; m_packet[ pos ].m_value = value; m_packet[ pos ].m_status = Status::Complete; ++m_count; return true; } bool pop ( Data & value ) { if ( m_count == 0 ) return false; uint32_t pos = ( m_read_head++ ) % MaxCount; Status expected = Status::Complete; while( !m_packet[ pos ].m_status.compare_exchange_weak( expected, Status::Proceed ) ) expected = Status::Complete; value = m_packet[ pos ].m_value; //m_packet[ pos ].m_value = Data(); m_packet[ pos ].m_status = Status::Empty; --m_count; return true; }}; static Buffer global_buffer;static std::atomic< uint32_t > write_count;static std::atomic< uint32_t > read_count; void pushValue (){ Data value; while( !global_buffer.push( value ) ); ++write_count;} void popValue (){ Data value; while( !global_buffer.pop( value ) ); ++read_count;} void write ( size_t count ){ for ( size_t i = 0; i < count; ++i ) pushValue();} void read ( size_t count ){ for ( size_t i = 0; i < count; ++i ) popValue();} int main ( int /*argc*/, char */*argv*/[] ){ std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); std::thread first_writer( write, 10000000 ); std::thread second_writer( write, 20000000 ); std::thread reader( read, 30000000 ); first_writer.join(); second_writer.join(); reader.join(); std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now(); std::cout << "Write count: " << write_count.load() << std::endl; std::cout << "Read count: " << read_count.load() << std::endl; std::cout << "Time elapsed: " << std::chrono::duration_cast< std::chrono::milliseconds >(end - begin).count() << "ms" << std::endl; return 0;}
C++ (Qt)typedef Data * DataPtr; struct Buffer{ enum { MaxCount = 0x0004 }; struct Packet { std::atomic< DataPtr > m_ptr; Packet () : m_ptr() {} }; std::atomic< uint32_t > m_write_head; std::atomic< uint32_t > m_read_head; std::atomic< uint32_t > m_count; Packet m_packets[ MaxCount ]; bool push ( DataPtr value ) { if ( m_count >= MaxCount ) return false; uint32_t pos = ( m_write_head++ ) % MaxCount; DataPtr expected = nullptr; while( !m_packets[ pos ].m_ptr.compare_exchange_weak( expected, value ) ) expected = nullptr; ++m_count; return true; } bool pop ( DataPtr & value ) { if ( m_count == 0 ) return false; uint32_t pos = ( m_read_head++ ) % MaxCount; while( ( value = m_packets[ pos ].m_ptr.exchange( nullptr ) ) == nullptr ); --m_count; return true; }}; static Buffer global_buffer;static std::atomic< uint32_t > write_count;static std::atomic< uint32_t > read_count; void pushValue (){ DataPtr value = new Data; while( !global_buffer.push( value ) ); ++write_count;} void popValue (){ DataPtr value = nullptr; while( !global_buffer.pop( value ) ); delete value; ++read_count;} void write ( size_t count ){ for ( size_t i = 0; i < count; ++i ) pushValue();} void read ( size_t count ){ for ( size_t i = 0; i < count; ++i ) popValue();} int main ( int /*argc*/, char */*argv*/[] ){ std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); std::thread first_writer( write, 10000000 ); std::thread second_writer( write, 20000000 ); std::thread reader( read, 30000000 ); first_writer.join(); second_writer.join(); reader.join(); std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now(); std::cout << "Write count: " << write_count.load() << std::endl; std::cout << "Read count: " << read_count.load() << std::endl; std::cout << "Time elapsed: " << std::chrono::duration_cast< std::chrono::milliseconds >(end - begin).count() << "ms" << std::endl; return 0;}
C++ (Qt) if ( m_count >= MaxCount ) return false;