Skip to content

Commit c37c27b

Browse files
committed
Explain the new try_emplace method
1 parent 4ea3a3e commit c37c27b

1 file changed

Lines changed: 52 additions & 8 deletions

File tree

examples/README.md

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,30 +38,74 @@ There are three primary ways to write to the queue, each suited for a different
3838
3939
### High-Frequency Writes: `WriteTransaction`
4040
41-
This is the **highest-performance method** for producers that generate many individual items in a tight loop. It amortizes the cost of atomic operations over many fast, non-atomic pushes.
41+
This is the **highest-performance API** for producers that generate many individual items in a tight loop. It amortizes the high cost of atomic synchronization over many fast, non-atomic pushes and emplaces.
42+
43+
The process involves three steps:
44+
1. Start a transaction for a batch of items using `try_start_write()`.
45+
2. If successful, use the transaction object's ultra-fast `try_emplace()` or `try_push()` methods to add items to the reserved space.
46+
3. The transaction automatically commits the items that were successfully added when its `WriteTransaction` object is destroyed.
47+
48+
#### The `try_emplace` Method (Recommended for Complex Objects)
49+
50+
`try_emplace` is the most efficient way to add a complex object to the queue. It constructs the object **in-place** directly in the queue's memory, avoiding any temporary objects or expensive move operations.
51+
52+
```cpp
53+
#include <string>
54+
#include <vector>
55+
56+
struct MyData {
57+
std::string s;
58+
std::vector<int> v;
59+
MyData(const std::string& str, size_t n) : s(str), v(n) {}
60+
};
61+
62+
void emplace_producer(LockFreeSpscQueue<MyData>& queue)
63+
{
64+
// Try to start a transaction for up to 16 items.
65+
if (auto transaction = queue.try_start_write(16))
66+
{
67+
// We got a reservation! Emplace items directly into it.
68+
// This is extremely fast, as there are no temporary MyData objects.
69+
transaction->try_emplace("hello", 100);
70+
transaction->try_emplace("world", 200);
71+
72+
// 'transaction' automatically commits the 2 new items when it goes out of scope.
73+
}
74+
}
75+
```
76+
77+
#### The `try_push` Method (For Simple Types or Pre-existing Objects)
78+
79+
`try_push` is ideal for trivial types (like `int` or `float`) or when you already have an existing object that you want to move into the queue.
4280

4381
```cpp
4482
void high_frequency_producer(LockFreeSpscQueue<Message>& queue)
4583
{
46-
for (int i = 0; i < 100; ) {
47-
// 1. Try to start a transaction for a batch of up to 16 items.
84+
int next_item = 0;
85+
86+
// Keep writing until we've sent 100 items.
87+
while (next_item < 100)
88+
{
89+
// 1. Try to start a transaction for a batch of up to 32 items.
4890
// This returns an optional; it will be empty if the queue is too full.
49-
if (auto transaction = queue.try_start_write(16)) {
91+
if (auto transaction = queue.try_start_write(32))
92+
{
5093
// 2. We got a reservation! Push items into it.
51-
// This `try_push` is extremely fast (non-atomic).
52-
while (i < 100 && transaction->try_push({i, "some data"})) {
94+
// Use try_push for this simple integer type.
95+
while (next_item < 100 && transaction->try_push(next_item)) {
5396
// Item was successfully pushed into the transaction's reserved space.
54-
i++;
97+
next_item++;
5598
}
5699
// 3. The transaction automatically commits the items that were
57100
// pushed when it goes out of scope here.
58101
} else {
59-
// Queue was too full to even start a transaction, yield to the consumer.
102+
// The queue was too full to even start a transaction, yield to the consumer.
60103
std::this_thread::yield();
61104
}
62105
}
63106
}
64107
```
108+
65109
*Move semantics are also supported: `transaction->try_push(std::move(my_message));`*
66110
67111
### Batch Writes (Convenience): `try_write`

0 commit comments

Comments
 (0)