-
Notifications
You must be signed in to change notification settings - Fork 1.7k
refactor(samples): replace pthreads with std::thread in multithreaded sample #13733
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a569a97
62189d5
b32e26d
3310fe1
d7b9c2c
f75761b
7005da9
099970d
c7eef6c
3b47e67
9c4796e
7b08175
1acd5a4
d9335fa
7f835f0
eab01ac
c9b5be7
016ce5e
90ce521
a6f8056
de11942
5450c49
07478e2
2441261
d74bfea
2bae38b
64f84a7
c6df027
85e75c7
3997993
840ff01
e269fcb
fa931f6
93a3f97
5726a19
5bf13ce
1a50084
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,63 @@ | ||
{ | ||
// See https://go.microsoft.com/fwlink/?LinkId=733558 | ||
// for the documentation about the tasks.json format | ||
"version": "2.0.0", | ||
"tasks": [ | ||
{ | ||
"label": "build", | ||
"type": "shell", | ||
"group": { | ||
"kind": "build", | ||
"isDefault": true | ||
}, | ||
"presentation": { | ||
"echo": true, | ||
"reveal": "always", | ||
"focus": false, | ||
"panel": "shared" | ||
}, | ||
"windows": { | ||
"command": "${workspaceRoot}/build.cmd", | ||
"args": [ | ||
"<Path/To/MinGW/Cygwin/Bin/Folder>", // Path to the bin folder containing g++ to compile | ||
"fib.exe" // Output executable name | ||
] | ||
}, | ||
"linux": { | ||
"command": "g++", | ||
"args": [ | ||
"-g", | ||
"*.cpp", | ||
"-lpthread", | ||
"--std=c++11", | ||
"-o", | ||
"fib.out" | ||
] | ||
}, | ||
"osx": { | ||
"command": "g++", | ||
"args": [ | ||
"-g", | ||
"*.cpp", | ||
"-lpthread", | ||
"--std=c++11", | ||
"-o", | ||
"fib.out" | ||
] | ||
} | ||
|
||
"version": "2.0.0", | ||
"tasks": [ | ||
{ | ||
"label": "build (Windows)", | ||
"type": "shell", | ||
"command": "build.cmd", | ||
"group": { | ||
"kind": "build", | ||
"isDefault": true | ||
}, | ||
"windows": { | ||
"command": "build.cmd" | ||
}, | ||
"problemMatcher": ["$msCompile"], | ||
"options": { | ||
"cwd": "${workspaceFolder}" | ||
} | ||
}, | ||
{ | ||
"label": "build (Linux/macOS)", | ||
"type": "shell", | ||
"command": "make", | ||
"group": { | ||
"kind": "build", | ||
"isDefault": true | ||
}, | ||
Subham-KRLX marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"linux": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the makefile was removed in favor of calling g++ for all platforms, it looks like this task can be removed. The 'make clean' task can also be removed (or changed to delete the binary directly). |
||
"command": "make" | ||
}, | ||
"osx": { | ||
"command": "make" | ||
}, | ||
"problemMatcher": ["$gcc"], | ||
"options": { | ||
"cwd": "${workspaceFolder}" | ||
} | ||
}, | ||
{ | ||
"label": "clean (Windows)", | ||
"type": "shell", | ||
"command": "del /Q fib.exe", | ||
"options": { | ||
"cwd": "${workspaceFolder}", | ||
"shell": { | ||
"executable": "cmd.exe", | ||
"args": ["/C"] | ||
} | ||
] | ||
} | ||
}, | ||
{ | ||
"label": "clean (Linux/macOS)", | ||
"type": "shell", | ||
"command": "make clean", | ||
"options": { | ||
"cwd": "${workspaceFolder}" | ||
} | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the makefile was removed, this needs to be updated. |
||
|
||
# Windows (MinGW) | ||
g++ -std=c++11 -pthread -o fib.exe main.cpp thread.cpp |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
SET PATH=%PATH%;%1 | ||
g++ -g *.cpp -lpthread --std=c++11 -O0 -o %2 | ||
@echo off | ||
Subham-KRLX marked this conversation as resolved.
Show resolved
Hide resolved
|
||
g++ -std=c++11 -pthread -g -O0 -o fib.exe main.cpp thread.cpp |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,69 @@ | ||
#include <iostream> | ||
#include <unistd.h> | ||
#include <sys/types.h> | ||
#include <pthread.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <time.h> | ||
#include <string.h> | ||
|
||
#include <thread> | ||
#include <vector> | ||
#include <cstdlib> | ||
#include <ctime> | ||
#include <cstring> | ||
#include <atomic> | ||
#include <chrono> | ||
#include <csignal> | ||
#include <unistd.h> | ||
#include "thread.h" | ||
|
||
#define THREAD_COUNT 10 | ||
|
||
static char block[] = "--block"; | ||
int test = 0; | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
srand(time(NULL)); | ||
static constexpr char block[] = "--block"; | ||
static constexpr char crash[] = "--crash"; | ||
static constexpr char test_flag[] = "--test"; | ||
|
||
static char pidText[] = "PID: "; | ||
std::string helpText = "Attach a debugger and execute 'set foo=0' to continue"; | ||
char helloText[] = "Hello World!"; | ||
volatile std::sig_atomic_t g_signal_status = 0; | ||
|
||
std::cout << helloText << std::endl; | ||
|
||
pthread_t threads[THREAD_COUNT]; | ||
|
||
if (argc == 2 && !strcmp(block, argv[1])) | ||
{ | ||
std::cout << helpText << std::endl; | ||
volatile int foo = 1; | ||
while (foo) | ||
; | ||
} | ||
void signal_handler(int signal) { | ||
g_signal_status = signal; | ||
} | ||
|
||
if (argc == 2 && !strcmp("--crash", argv[1])) | ||
{ | ||
int foo = 0; | ||
int bar = 1 / foo; | ||
int main(int argc, char **argv) | ||
{ | ||
std::signal(SIGINT, signal_handler); | ||
std::cout << "Hello World!" << std::endl; | ||
|
||
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; | ||
std::atomic<int> foo{1}; // Changed from volatile | ||
while (foo.load() && 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; | ||
std::atomic<int> foo{0}; // Changed from volatile | ||
std::atomic<int> bar{1 / foo.load()}; // Changed from volatile and added .load() | ||
(void)bar; | ||
return 1; | ||
} | ||
else if (std::strcmp(test_flag, argv[1]) == 0) { | ||
std::cout << "Running in test mode" << std::endl; | ||
} | ||
} | ||
|
||
for (int i = 0; i < THREAD_COUNT; i++) | ||
{ | ||
std::cout << "Test " << i << std::endl; | ||
pthread_create(&threads[i], NULL, &thread_proc, NULL); | ||
|
||
std::vector<std::thread> threads; | ||
threads.reserve(THREAD_COUNT); | ||
|
||
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++; | ||
for (auto& t : threads) { | ||
if (t.joinable()) { | ||
t.join(); | ||
} | ||
} | ||
|
||
std::cout << "All threads exited!" << std::endl; | ||
|
||
return 1; | ||
|
||
std::cout << "\nAll " << threads.size() << " threads completed successfully!" << std::endl; | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,42 @@ | ||
#include <iostream> | ||
#include <unistd.h> | ||
#include <sys/types.h> | ||
#include <pthread.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <time.h> | ||
#include <string.h> | ||
|
||
#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 <thread> | ||
#include <chrono> | ||
#include <atomic> | ||
#include <string> | ||
#include <random> | ||
#include <mutex> | ||
|
||
static std::atomic<int> g_tid{0}; | ||
static std::mutex cout_mutex; | ||
|
||
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); | ||
#else | ||
pthread_setname_np(pthread_self(), thread_name); | ||
#endif | ||
static thread_local std::mt19937_64 rng{std::random_device{}()}; | ||
|
||
// 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); | ||
static int intRand(int min, int max) { | ||
return std::uniform_int_distribution<int>(min, max)(rng); | ||
} | ||
|
||
volatile int i = 0; | ||
while (i <= 30) { | ||
std::cout << "Thread " << tid << ": fib(" << i << ") = " << fib(i) << std::endl; | ||
i++; | ||
nanosleep(&ts, NULL); | ||
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); | ||
|
||
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<std::mutex> lock(cout_mutex); | ||
std::cout << thread_name << ": fib(" << i << ") = " << fib(i) << std::endl; | ||
} | ||
std::this_thread::sleep_for(delay); | ||
} | ||
|
||
std::cout << thread_name << " exited!" << std::endl; | ||
} | ||
|
||
{ | ||
std::lock_guard<std::mutex> lock(cout_mutex); | ||
std::cout << thread_name << " exited!" << std::endl; | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.