cppbuilder

Dealing with Sharing C++

If you don’t use Sharing C++, no data races can happen. Not sharing means that your thread works on local variables. This can be achieved by copying the value, using thread-specific storage, or transferring the result of a thread to its associated future via a protected data channel. The patterns in this section are quite obvious, but I will present them with a short explanation for completeness. Let me start with Copied Value. Copied Value Sharing C++ If a thread gets its arguments by copy and not by reference, there is no need to synchronize access to any data. No data races and no lifetime issues are possible. Data Races with References The following program creates three threads. One thread gets its argument by copy, the other by reference, and the last by constant reference. // copiedValueDataRace.cpp #include #include #include #include using namespace std::chrono_literals; void byCopy(bool b){ std::this_thread::sleep_for(1ms); // (1) std::cout << “byCopy: ” << b << ‘n’; } void byReference(bool& b){ std::this_thread::sleep_for(1ms); // (2) std::cout << “byReference: ” << b << ‘n’; } void byConstReference(const bool& b){ std::this_thread::sleep_for(1ms); // (3) std::cout << “byConstReference: ” << b << ‘n’; } int main(){ std::cout << std::boolalpha << ‘n’; bool shared{false}; std::thread t1(byCopy, shared); std::thread t2(byReference, std::ref(shared)); std::thread t3(byConstReference, std::cref(shared)); shared = true; t1.join(); t2.join(); t3.join(); std::cout << ‘n’; } Each thread sleeps for one millisecond (lines 1, 2, and 3) before displaying the boolean value. Only the thread t1 has a local copy of the boolean and has, therefore, no data race. The program’s output shows that the boolean values of threads t2 and t3 are modified without synchronization. You may think that the thread t3 in the previous example copiedValueDataRace.cpp can just be replaced with std::thread t3(byConstReference, shared). The program compiles and runs, but what seems like a reference is a copy. The reason is that the type traits function std::decay is applied to each thread argument. std::decay performs lvalue-to-rvalue, array-to-pointer, and function-to-pointer implicit conversions to its type T. In particular, it invokes, in this case, the type traits function std::remove_reference on the type T. The following program perConstReference.cpp uses a non-copyable type NonCopyableClass. // perConstReference.cpp #include class NonCopyableClass{ public: // the compiler generated default constructor NonCopyableClass() = default; // disallow copying NonCopyableClass& operator = (const NonCopyableClass&) = delete; NonCopyableClass (const NonCopyableClass&) = delete; }; void perConstReference(const NonCopyableClass& nonCopy){} int main(){ NonCopyableClass nonCopy; // (1) perConstReference(nonCopy); // (2) std::thread t(perConstReference, nonCopy); // (3) t.join(); } The object nonCopy (line 1) is not copyable. This is fine if I invoke the function perConstReference with the argument nonCopy (line 2) because the function accepts its argument per constant reference. Using the same function in the thread t (line 3) causes GCC to generate a verbose compiler error with more than 300 lines: The error message’s essential part is in the middle of the screenshot in red rounded rectangle: “error: use of deleted function”. The copy-constructor of the class NonCopyableClass is not available. When you borrow something, you have to ensure that the underlying value is still available when you use it. Lifetime Issues with References If a thread uses its argument by reference and you detach the thread, you have to be extremely careful. The small program copiedValueLifetimeIssues.cpp has undefined behavior. // copiedValueLifetimeIssues.cpp #include #include #include void executeTwoThreads(){ // (1) const std::string […]

Read More

C++ Builder Multi-Device application with Platform APIs

C++ Builder Multi-Device application provides three levels of development: ⦁ Components (VCL and FMX)⦁ Common Libraries (RTL).⦁ Platform APIs (iOS, Android, Mac OS) In this post we will discuss and show how to use the Platform APIs (iOS, Android, Mac OS). Specifically, we’ll look at how to use the iOS APIs to obtain Apple iOS device information for the Operating System (OS) version, the OS name and the iOS device type. Some refer to this as being able to ‘Touch the Metal’ of the device, meaning having access to the low level APIs of the device. The C++ Builder Run Time Library (RTL) includes a number of header files that provide C++ interfaces to the iOS frameworks written in Objective-C. And C++ Builder has the same for Android for the Java Libraries for Android, to allow you to access the APIs of the Android Java libraries from your native C++ code. For Apple IOS, using C++ Builder, these units are scoped with iOSapi and are installed by default in your installation folder \include\ios\rtl.  For Example: The complete list of these units are listed on this C++ Builder DocWiki page iOS Objective-C Frameworks (iOSapi) The C++ Builder FireMonkey framework relies on some of these units. For help on these iOS APIs, you can see the Apple documentation at iOS Developer Library To get to the iOS device information we need, we will need to use the iOS Objective-C Framework for:  iOSapi.UIKit.hpp Note:  The iOSapi.UIKit.hpp also includes the iOSapi.Foundation.hpp and the Macapi.Helpers (Macapi.ObjectiveC.hpp): 123 #define Iosapi_UikitHPP#include <iOSapi.Foundation.hpp>#include <Macapi.ObjectiveC.hpp> Here are steps to create a C++ Builder Multi-Device application to display Apple iOS device information for the Operating System (OS) version, the OS name and the iOS device type: Create a new C++ Builder Multi-Device application, BLANK. Target Platform = iOS 64-bit. Save Project in a new Folder, such as /Projects/CppiOSDeviceInfo Use Project | Options | Deployment | Provisioning, to select your Apple Provisioning Profile and your Developer Certificate: 4. Use Project | Options | Application | Version Info | to enter your unique Application Identifier for the CFBundleIdentifier: Q4X27M46Z4.$(ModuleName) 5. In our C++ Builder Multi-Device iOS application, we will include this one header file:  #include <iOSapi.UIKit.hpp> 1234 #include <fmx.h>#include <iOSapi.UIkit.hpp>  // iOS Device information#pragma hdrstop#include “uMain.h” 6. For the User Interface (UI), create a UI that look like this: 7. To create this UI, follow these steps: On your Blank form in your new C++ Builder Multi-Device application: a. Add a Toolbar, property Align = Top. b. On the Toolbar, add a Button, Align = Right. Button Name = btnGetDeviceInfo. StyleLookup = refreshtoolbuttonbordered. c. On the Toolbar, add a Label, Align = Contents. Label->Text = Device Information d. To display the iOS Device information we will use a ListBox. Add ListBox to the form. Align = Top. e. To the ListBox, add three (3) ListBoxItems, to display the OS version, the OS name and the iOS device type.  To do this, in the Structure Pane, Right-click on ListBox1, Items Editor, Select ListBoxItem from the dropdown, Click Add item button 3 times. Rename ListBoxItem’s TEXT values as OS Name:, Device Type:, and OS Version, and ListBoxItem.Name = lbOSName , lbDeviceType, and lbOSVersion , respectively. 8. You can now double-click on the button for GetDeviceInfo and for it’s OnClick Event Handler, and you can use the functions and methods in the iOSapi UIKit header file to get OS information from our iOS device. 9. First, in your C++ Builder IDE, lets look at the iOSapi.UIKit.hpp header file.  In the IDE Editor, select the iOSapi.UIKit.hpp | Right-Click | Open File At Cursor.  This should open the iOSapi.UIKit.hpp header file in the Editor. 10. Looking at the “Methods Insite” dropdown, […]

Read More