diff --git a/Code Samples/Fib/.vscode/launch.json b/Code Samples/Fib/.vscode/launch.json index 301f8c5f2..4fe3af585 100644 --- a/Code Samples/Fib/.vscode/launch.json +++ b/Code Samples/Fib/.vscode/launch.json @@ -3,38 +3,29 @@ "configurations": [ { "name": "(gdb) Launch", - "preLaunchTask": "build", "type": "cppdbg", "request": "launch", + "program": "${workspaceFolder}/fib.out", "args": [], - "stopAtEntry": true, - "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "cwd": "${workspaceFolder}", "environment": [], - "externalConsole": true, + "externalConsole": false, + "MIMode": "gdb", "setupCommands": [ { - "description": "Enable pretty-printing for gdb", + "description": "Enable pretty-printing", "text": "-enable-pretty-printing", "ignoreFailures": true } ], - "logging": { - "engineLogging": false, - "trace": false - }, "windows": { - "program": "${workspaceRoot}/fib.exe", - "MIMode": "gdb", + "program": "${workspaceFolder}/fib.exe", "miDebuggerPath": "" // Path to gdb on windows }, "linux": { - "program": "${workspaceRoot}/fib.out", - "MIMode": "gdb" - }, - "osx": { - "program": "${workspaceRoot}/fib.out", - "MIMode": "lldb" + "program": "${workspaceRoot}/fib.out" } } ] -} \ No newline at end of file +} diff --git a/Code Samples/Fib/.vscode/tasks.json b/Code Samples/Fib/.vscode/tasks.json index 104a10aad..c4df36f93 100644 --- a/Code Samples/Fib/.vscode/tasks.json +++ b/Code Samples/Fib/.vscode/tasks.json @@ -1,50 +1,64 @@ { - // See https://go.microsoft.com/fwlink/?LinkId=733558 + // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ { - "label": "build", + "label": "build (Unix)", "type": "shell", + "command": "make", "group": { "kind": "build", "isDefault": true }, - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "shared" + "problemMatcher": ["$gcc"], + "options": { + "cwd": "${workspaceFolder}" }, - "windows": { - "command": "${workspaceRoot}/build.cmd", - "args": [ - "", // Path to the bin folder containing g++ to compile - "fib.exe" // Output executable name - ] + "detail": "Build using Makefile (Linux/macOS)" + }, + { + "label": "build (Windows)", + "type": "shell", + "command": "g++ -std=c++11 -pthread -o fib.exe main.cpp thread.cpp", + "group": "build", + "problemMatcher": ["$gcc"], + "options": { + "cwd": "${workspaceFolder}" }, - "linux": { - "command": "g++", - "args": [ - "-g", - "*.cpp", - "-lpthread", - "--std=c++11", - "-o", - "fib.out" - ] + "detail": "Build using g++ (Windows/MinGW)", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/C"] + } + } + } + }, + { + "label": "clean (Unix)", + "type": "shell", + "command": "make clean", + "options": { + "cwd": "${workspaceFolder}" + } + }, + { + "label": "clean (Windows)", + "type": "shell", + "command": "del /Q fib.exe", + "options": { + "cwd": "${workspaceFolder}" }, - "osx": { - "command": "g++", - "args": [ - "-g", - "*.cpp", - "-lpthread", - "--std=c++11", - "-o", - "fib.out" - ] + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/C"] + } + } } } ] -} +} \ No newline at end of file diff --git a/Code Samples/Fib/Makefile b/Code Samples/Fib/Makefile new file mode 100644 index 000000000..c53dfc2ac --- /dev/null +++ b/Code Samples/Fib/Makefile @@ -0,0 +1,20 @@ +CXX := g++ +CXXFLAGS := -std=c++11 -Wall -Wextra +SRCS := main.cpp thread.cpp +OBJS := $(SRCS:.cpp=.o) +TARGET := fib_sample + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CXX) $(OBJS) -o $@ + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) $(TARGET) + + + + \ No newline at end of file diff --git a/Code Samples/Fib/README.md b/Code Samples/Fib/README.md index 6402c911b..e1d27d65e 100644 --- a/Code Samples/Fib/README.md +++ b/Code Samples/Fib/README.md @@ -1,3 +1,28 @@ -# Fib +# Fibonacci Debugging Sample -This code sample is to show debugging. Update `launch.json` and `tasks.json` in the `.vscode` folder to use your setup to build and debug. \ No newline at end of file +This sample demonstrates C++ debugging capabilities in VS Code using a multithreaded Fibonacci number generator. + +## Features +- Modern C++ implementation using `std::thread` +- Cross-platform debugging configuration +- Multiple debugging scenarios: + - Breakpoint debugging + - Conditional breakpoints + - Watch expressions + - Crash investigation + - Debugger attachment + +## Getting Started + +### Prerequisites +- C++ compiler (g++/clang/MSVC) +- VS Code with C++ extension +- Debugger (gdb/lldb/MSVC debugger) + +### Building +```bash +# Linux/macOS +make + +# Windows (MinGW) +g++ -std=c++11 -pthread -o fib.exe main.cpp thread.cpp \ No newline at end of file diff --git a/Code Samples/Fib/build.cmd b/Code Samples/Fib/build.cmd deleted file mode 100644 index 821c62747..000000000 --- a/Code Samples/Fib/build.cmd +++ /dev/null @@ -1,2 +0,0 @@ -SET PATH=%PATH%;%1 -g++ -g *.cpp -lpthread --std=c++11 -O0 -o %2 \ No newline at end of file diff --git a/Code Samples/Fib/main.cpp b/Code Samples/Fib/main.cpp index e7ab0c4c9..bada7839e 100644 --- a/Code Samples/Fib/main.cpp +++ b/Code Samples/Fib/main.cpp @@ -1,58 +1,91 @@ #include -#include -#include -#include -#include -#include -#include -#include - +#include +#include +#include +#include +#include +#include +#include +#include +#include // Required for getpid() #include "thread.h" #define THREAD_COUNT 10 -static char block[] = "--block"; -int test = 0; +static constexpr char block[] = "--block"; +static constexpr char crash[] = "--crash"; +static constexpr char test_flag[] = "--test"; +std::atomic test_count{0}; // Thread-safe counter +volatile std::sig_atomic_t g_signal_status = 0; + +void signal_handler(int signal) { + g_signal_status = signal; +} int main(int argc, char **argv) { - srand(time(NULL)); + // Register signal handler for clean interruption + std::signal(SIGINT, signal_handler); - static char pidText[] = "PID: "; - std::string helpText = "Attach a debugger and execute 'set foo=0' to continue"; - char helloText[] = "Hello World!"; + // Initialize random seed + std::srand(static_cast(std::time(nullptr))); - std::cout << helloText << std::endl; + std::cout << "Hello World!" << std::endl; - pthread_t threads[THREAD_COUNT]; + if (argc == 2) { + if (std::strcmp(block, argv[1]) == 0) { + std::cout << "Attach a debugger and set foo=0 to continue" << std::endl; + std::cout << "Process ID: " << getpid() << std::endl; - if (argc == 2 && !strcmp(block, argv[1])) - { - std::cout << helpText << std::endl; - volatile int foo = 1; - while (foo) - ; + volatile int foo = 1; + while (foo && g_signal_status == 0) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "Waiting... (press Ctrl-C to quit)" << std::endl; + } + return 0; + } + else if (std::strcmp(crash, argv[1]) == 0) { + std::cout << "Triggering intentional crash..." << std::endl; + volatile int foo = 0; + volatile int bar = 1 / foo; // Guaranteed crash + (void)bar; // Suppress unused-variable warning + return 1; // Unreachable after crash + } + else if (std::strcmp(test_flag, argv[1]) == 0) { + std::cout << "Running in test mode" << std::endl; + // Add any test-specific code here + } } - if (argc == 2 && !strcmp("--crash", argv[1])) - { - int foo = 0; - int bar = 1 / foo; - } + // Thread management + std::vector threads; + threads.reserve(THREAD_COUNT); - for (int i = 0; i < THREAD_COUNT; i++) - { - std::cout << "Test " << i << std::endl; - pthread_create(&threads[i], NULL, &thread_proc, NULL); - } + try { + // Create and launch threads + for (int i = 0; i < THREAD_COUNT; ++i) { + std::cout << "Launching thread " << i << std::endl; + threads.emplace_back(thread_proc); + } - for (int i = 0; i < THREAD_COUNT; i++) - { - pthread_join(threads[i], NULL); - test++; + // Join all threads + for (auto& t : threads) { + if (t.joinable()) { + t.join(); + test_count.fetch_add(1, std::memory_order_relaxed); + } + } + } + catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + for (auto& t : threads) { + if (t.joinable()) { + t.detach(); + } + } + return 1; } - std::cout << "All threads exited!" << std::endl; - - return 1; + std::cout << "\nAll " << test_count.load() << " threads completed successfully!" << std::endl; + return 0; } diff --git a/Code Samples/Fib/thread.cpp b/Code Samples/Fib/thread.cpp index bef34e9c7..7fa9dbf44 100644 --- a/Code Samples/Fib/thread.cpp +++ b/Code Samples/Fib/thread.cpp @@ -1,48 +1,61 @@ #include -#include -#include -#include -#include -#include -#include -#include - -#include "thread.h" - -static int g_tid = 0; - -static int fib(int n){ - switch (n) { - case 0: return 1; - case 1: return 1; - default: return (fib(n-2) + fib(n-1)); - } +#include +#include +#include +#include +#include +#include + +// Thread-safe counter for thread IDs +static std::atomic g_tid{0}; + +// Mutex for thread-safe console output +static std::mutex cout_mutex; + +// Generate fibonacci numbers recursively (memoization would be better) +static int fib(int n) { + if (n <= 1) return 1; + return fib(n - 1) + fib(n - 2); } -void * thread_proc(void* ctx) -{ - int tid = g_tid++; - - char thread_name[16]; - sprintf(thread_name, "Thread %d", tid); -#ifdef __APPLE__ - pthread_setname_np(thread_name); +// Cross-platform thread naming (C++20 would use std::jthread) +static void set_thread_name(const std::string& name) { +#ifdef __cpp_lib_jthread + // Future C++20 implementation + // std::jthread::set_name(name); #else - pthread_setname_np(pthread_self(), thread_name); + // Current placeholder #endif +} - // Random delay, 0 - 0.5 sec - timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = 500000000 + ((float)rand() / (float)RAND_MAX) * 500000000; - nanosleep(&ts, NULL); - - volatile int i = 0; - while (i <= 30) { - std::cout << "Thread " << tid << ": fib(" << i << ") = " << fib(i) << std::endl; - i++; - nanosleep(&ts, NULL); +// Thread-local RNG for random delays +static thread_local std::mt19937_64 rng{std::random_device{}()}; + +// Uniform integer generator +static int intRand(int min, int max) { + return std::uniform_int_distribution(min, max)(rng); +} + +void thread_proc() { + const int tid = g_tid.fetch_add(1, std::memory_order_relaxed); + const std::string thread_name = "Thread " + std::to_string(tid); + set_thread_name(thread_name); + + const auto delay = std::chrono::nanoseconds(500000000 + intRand(0, 500000000)); + + std::this_thread::sleep_for(delay); + + for (int i = 0; i <= 30; ++i) { + { + std::lock_guard lock(cout_mutex); + std::cout << thread_name << ": fib(" << i << ") = " << fib(i) << std::endl; + } + std::this_thread::sleep_for(delay); + } + + { + std::lock_guard lock(cout_mutex); + std::cout << thread_name << " exited!" << std::endl; } +} - std::cout << thread_name << " exited!" << std::endl; -} \ No newline at end of file diff --git a/Code Samples/Fib/thread.h b/Code Samples/Fib/thread.h index 6af19e651..66fc50ac5 100644 --- a/Code Samples/Fib/thread.h +++ b/Code Samples/Fib/thread.h @@ -1 +1,8 @@ -void * thread_proc(void* ctx); +#pragma once + +/** + * @brief Launches a background thread computing Fibonacci numbers with random delays. + */ +void thread_proc(); + +