Code: Select all
#include
#include
#include
int main() {
std::atomic key;
auto t1 = std::thread([&]() {
auto now = std::chrono::steady_clock::now();
auto duration = now.time_since_epoch();
auto seconds =
std::chrono::duration_cast(duration).count();
key.store(seconds); // #1 occurred at timepoint `T1`
});
auto t2 = std::thread([&]() {
auto now = std::chrono::steady_clock::now();
auto duration = now.time_since_epoch();
auto seconds =
std::chrono::duration_cast(duration).count();
key.store(seconds); // #2 occurred at timepoint `T2`
});
auto t3 = std::thread([&]() {
std::this_thread::sleep_for(std::chrono::milliseconds(300)); // debounce
auto search_key = key.load(); // #3 occurred at timepoint `T3`
// request(search_key);
});
t1.join();
t2.join();
t3.join();
}
In diesem Beispiel werden die beiden Eingabeereignisse des Benutzers modelliert, nämlich t1 und t2. Angenommen, jedes Ereignis trat zu dem im Kommentar angegebenen Zeitpunkt auf und T1 < T2 < T3. Auch wenn jede atomare Operation seq_cst verwendet und eine einzige Gesamtreihenfolge bildet und die Zeitpunkte T1 und T2 beide vor T3 liegen, kann #3 immer noch #1 laden und vor #2 kohärenzgeordnet sein.
Dies ist keine Linearisierbarkeit, da T1 < T2 < T3 und die Ladung bei T3 den Speicher nicht gelesen haben das geschah bei T2. (Ich bin mir nicht sicher, ob die Konsistenz in der Zeitleiste als Linearisierbarkeit bezeichnet werden kann).
Ist es also aus Sicht des C++-Standards wahr, dass nur ein einzelner Thread Linearisierbarkeit garantieren kann? Das heißt, der Ladevorgang liest garantiert immer den Speicher, der vor dem Ladevorgang am nächsten an der Zeitachse stattfand.
Update-Beispiel
Code: Select all
#include
#include
#include
int main() {
std::atomic key;
auto t3 = std::thread([&]() {
std::this_thread::sleep_for(std::chrono::milliseconds(300)); // debounce
auto search_key = key.load(); // C
// request(search_key);
if(search_key==key.load()){ // D
// use the response
}
});
key.store(1); // A first input
key.store(2); // B second input
t3.join();
}
Code: Select all
ADer vollständige Fall besteht darin, eine Suchaufgabe für jede Eingabe des Benutzers zu erstellen und die Antwort zu verwerfen, wenn sich der Wert geändert hat, um zu modellieren, was in Javascript geschieht
Code: Select all
#include
#include
#include
#include
#include
#include
#include
#include
// =================================================================
// 1. TASK DISPATCHER (The "Event Loop")
// This class mimics the JavaScript Task Queue. It allows background
// threads to "post" work back to the main thread for execution.
// =================================================================
class Dispatcher {
std::queue tasks;
std::mutex mtx;
public:
// Pushes a function into the queue. Safe to call from any thread.
void post(std::function task) {
std::lock_guard lock(mtx);
tasks.push(task);
}
// Executes all pending tasks. Should be called by the Main Thread.
void processEvents() {
std::queue toExecute;
{
// Swap content to minimize lock time (prevents blocking posters)
std::lock_guard lock(mtx);
std::swap(toExecute, tasks);
}
while (!toExecute.empty()) {
toExecute.front()(); // Execute the callback
toExecute.pop();
}
}
};
Dispatcher g_dispatcher; // Global dispatcher acting as our event loop
// =================================================================
// 2. MOCK NETWORK FUNCTION
// Simulates an asynchronous network request.
// =================================================================
void fetchNetworkData(int inputValue, std::function callback) {
// Start a background thread to simulate network latency
std::thread([inputValue, callback]() {
// Simulate a 2-second delay
std::this_thread::sleep_for(std::chrono::seconds(2));
std::string result = "Data_for_" + std::to_string(inputValue);
// IMPORTANT: Instead of running the callback here (in the background thread),
// we post it back to the dispatcher so it runs on the Main Thread.
g_dispatcher.post([callback, result]() {
callback(result);
});
}).detach();
}
// =================================================================
// 3. SEARCH COMPONENT
// Handles the core logic: capturing input and validating responses.
// =================================================================
class SearchComponent {
int m_latestValue = -1; // State: holds the most recent input from the user
public:
void onUserInput(int newValue) {
m_latestValue = newValue;
std::cout
Mobile version