You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SQLite is a lightweight, serverless, self-contained SQL database engine commonly used for embedded applications and local data storage. The C++ delegate library is a multi-threaded framework capable of anonymously targeting any callable function, either synchronously or asynchronously. This delegate library is used to create an asynchronous API for SQLite. SQLite operates in a private thread of control, with all client API calls being invoked asynchronously on this private thread. The SQLite asynchronous wrapper makes no changes to the SQLite API, except for the addition of a trailing timeout argument for wait duration.
31
+
SQLite is a lightweight, serverless, self-contained SQL database engine commonly used for embedded applications and local data storage. The C++ DelegateMQ library is a multi-threaded framework capable of anonymously targeting any callable function, either synchronously or asynchronously.
31
32
32
-
The purpose of the wrapper is twofold: First, to provide a simple asynchronous layer over SQLite, and second, to serve as a working example of an asynchronous delegate library or subsystem interface.
33
+
This project leverages the delegate library to create a robust, thread-safe asynchronous wrapper for SQLite. All database operations are marshaled to a dedicated private worker thread, ensuring strict serialization of database access while freeing the client thread from blocking operations.
33
34
34
-
# References
35
+
**Key Features**
36
+
37
+
1.**Thread Safety:** A single background thread manages all SQLite interactions, preventing race conditions without complex client-side locking.
38
+
39
+
2.**Synchronous API (Blocking):** Wrappers that mimic the standard SQLite API but execute on the worker thread. The calling thread blocks until completion or a specified timeout occurs.
40
+
41
+
**Usage:* Ideal for linear logic where the result is needed immediately.
3.**Future API (Non-Blocking):** "Fire-and-Forget" functions that return a `std::future<int>` immediately. The main thread can continue processing UI updates or other tasks while the heavy SQL operation runs in the background.
45
+
46
+
**Usage:* Ideal for high-performance applications, UI responsiveness, and concurrent task processing.
* <ahref="https://github.com/endurodave/DelegateMQ">DelegatesMQ</a> - Invoke any C++ callable function synchronously, asynchronously, or on a remote endpoint.
37
52
* <ahref="https://www.sqlite.org/">SQLite</a> - SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine.
@@ -82,16 +97,21 @@ int main(void)
82
97
83
98
# Why Asynchronous SQLite
84
99
85
-
* **Improved Performance:** Offloading SQLite operations to a separate thread allows the main thread to remain responsive, enhancing overall application performance.
86
-
* **Non-blocking Operations:** By executing database queries in a separate thread, the main application thread can continue processing other tasks without waiting for SQLite operations to complete. A callback can be used to signal completion.
87
-
* **Atomic Operations:** Execute a series of database operations that cannot be interrupted without locks.
88
-
* **Isolation:** Running SQLite on a private thread ensures that database-related tasks are isolated from the main application logic, reducing the risk of thread contention or deadlock in the main application.
100
+
* **Thread Safety by Design:** SQLite handles are accessed exclusively by a single private worker thread. This serialization eliminates race conditions and removes the need for complex mutex locking code in your main application.
101
+
102
+
* **Responsive UI (Non-Blocking):** Using the Future API, expensive database operations (like bulk inserts or complex joins) are offloaded to the background. The main thread receives a `std::future` immediately, allowing it to keep the UI smooth and responsive while waiting for the result.
103
+
104
+
* **Flexible Control Flow:** The wrapper provides two distinct ways to interact with the database:
89
105
90
-
A side benefit is a real-world example of a multi-threaded application using the delegate library.
106
+
* **Synchronous:** Block and wait for a result (simple, linear logic for standard tasks).
107
+
108
+
* **Asynchronous:** "Fire-and-forget" using futures (high-concurrency for heavy tasks).
109
+
110
+
* **Sequential Atomicity:** Requests sent to the worker thread are executed in the exact order they are received. This allows you to safely dispatch a chain of dependent commands (e.g., `BEGIN`, multiple `INSERT`s, `COMMIT`) knowing they will run uninterrupted.
91
111
92
112
# Asynchronous SQLite
93
113
94
-
The file `async_sqlite3.h` implement the asynchronous interface. Each async function matches the SQLite library except the addition of a `timeout` argument.
114
+
The file `async_sqlite3.h` defines the asynchronous interface. Each async function matches the SQLite library except the addition of a `timeout` argument.
auto retVal = AsyncInvoke(::sqlite3_close, timeout, db);
176
-
return retVal;
193
+
return AsyncInvoke(::sqlite3_close, timeout, db);
177
194
}
178
195
179
196
// etc...
180
197
```
181
198
182
-
The `AsyncInvoke()` helper function invokes the function asynchronously if the caller is not executing on the `SQLiteThread` thread. Otherwise, if the caller is already on the internal thread the target function is called synchronously.
183
-
184
-
```cpp
185
-
// A private worker thread instance to execute all SQLite API functions
186
-
static Thread SQLiteThread("SQLite Thread");
187
-
188
-
/// Helper function to simplify asynchronous function calling on SQLiteThread
189
-
/// @param[in] func - a function to invoke
190
-
/// @param[in] timeout - the time to wait for invoke to complete
191
-
/// @param[in] args - the function argument(s) passed to func
This example illustrates how to utilize `std::future` for concurrent database operations. By leveraging the asynchronous API, you can implement a "Fire-and-Forget" pattern where the main thread remains fully responsive—performing UI updates or other processing—while heavy SQL operations execute in the background.
532
+
533
+
```cpp
534
+
voidexample_future()
535
+
{
536
+
printf_safe("\n--- Starting Example 5 (Future/Async) ---\n");
0 commit comments