-
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 6 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
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,50 +1,41 @@ | ||
| { | ||
| // 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", | ||
| "type": "shell", | ||
| "group": { | ||
| "kind": "build", | ||
| "isDefault": true | ||
| }, | ||
| "presentation": { | ||
| "echo": true, | ||
| "reveal": "always", | ||
| "focus": false, | ||
| "panel": "shared" | ||
| }, | ||
| "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": "g++", | ||
| "args": [ | ||
| "-g", | ||
| "*.cpp", | ||
| "-lpthread", | ||
| "--std=c++11", | ||
| "-o", | ||
| "fib.out" | ||
| ] | ||
| }, | ||
| "osx": { | ||
| "command": "g++", | ||
| "args": [ | ||
| "-g", | ||
| "*.cpp", | ||
| "-lpthread", | ||
| "--std=c++11", | ||
| "-o", | ||
| "fib.out" | ||
| ] | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| CXX := g++ | ||
Subham-KRLX marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| CXXFLAGS := -std=c++11 -Wall -Wextra -pthread | ||
sean-mcmanus marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| LDFLAGS := -pthread | ||
|
|
||
| SRCS := main.cpp thread.cpp | ||
| OBJS := $(SRCS:.cpp=.o) | ||
| TARGET := fib_sample | ||
|
|
||
| all: $(TARGET) | ||
|
|
||
| $(TARGET): $(OBJS) | ||
| $(CXX) $(OBJS) -o $@ $(LDFLAGS) | ||
|
|
||
| %.o: %.cpp | ||
| $(CXX) $(CXXFLAGS) -c $< -o $@ | ||
|
|
||
| clean: | ||
| rm -f $(OBJS) $(TARGET) | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,58 +1,91 @@ | ||
| #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> // 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<int> 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<unsigned>(std::time(nullptr))); | ||
Subham-KRLX marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| 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; | ||
Subham-KRLX marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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<std::thread> 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); | ||
Subham-KRLX marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| } | ||
| 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; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,48 +1,54 @@ | ||
| #include "thread.h" | ||
| #include <iostream> | ||
| #include <unistd.h> | ||
| #include <sys/types.h> | ||
| #include <thread> | ||
| #include <chrono> | ||
| #include <atomic> | ||
| #include <string> | ||
| #include <random> | ||
| #include <pthread.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <time.h> | ||
| #include <string.h> | ||
|
|
||
| #include "thread.h" | ||
|
|
||
| static int g_tid = 0; | ||
| // Thread-safe counter for thread IDs | ||
| static std::atomic<int> g_tid{0}; | ||
|
|
||
| static int fib(int n){ | ||
| // Generate fibonacci numbers recursively | ||
| static int fib(int n) { | ||
| switch (n) { | ||
| case 0: return 1; | ||
| case 1: return 1; | ||
| default: return (fib(n-2) + fib(n-1)); | ||
| default: 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); | ||
| // Set thread name (platform-specific) with Linux truncation | ||
| static void set_thread_name(const std::string& name) { | ||
Subham-KRLX marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #if defined(__APPLE__) | ||
| pthread_setname_np(name.c_str()); | ||
| #elif defined(__linux__) | ||
| std::string n = name.substr(0, 15); // limit ≤15 chars plus null (Linux limit) :contentReference[oaicite:0]{index=0} | ||
| pthread_setname_np(pthread_self(), n.c_str()); | ||
| #endif | ||
| } | ||
|
|
||
| // Thread-local RNG for good random delays | ||
| 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); | ||
|
|
||
| volatile int i = 0; | ||
| while (i <= 30) { | ||
| std::cout << "Thread " << tid << ": fib(" << i << ") = " << fib(i) << std::endl; | ||
| i++; | ||
| nanosleep(&ts, NULL); | ||
| // Uniform integer generator | ||
| static int intRand(int min, int max) { | ||
| return std::uniform_int_distribution<int>(min, max)(rng); | ||
| } | ||
|
|
||
| void thread_proc() { | ||
| int tid = g_tid.fetch_add(1, std::memory_order_relaxed); | ||
| std::string thread_name = "Thread " + std::to_string(tid); | ||
| set_thread_name(thread_name); | ||
|
|
||
| auto delay = std::chrono::nanoseconds(500000000 + intRand(0, 500000000)); | ||
|
|
||
| std::this_thread::sleep_for(delay); | ||
| for (int i = 0; i <= 30; ++i) { | ||
| std::cout << thread_name << ": fib(" << i << ") = " << fib(i) << "\n"; | ||
| std::this_thread::sleep_for(delay); | ||
| } | ||
|
|
||
| std::cout << thread_name << " exited!" << std::endl; | ||
| } | ||
| std::cout << thread_name << " exited!\n"; | ||
Subham-KRLX marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,8 @@ | ||
| void * thread_proc(void* ctx); | ||
| #pragma once | ||
|
|
||
| /** | ||
| * @brief Launches a background thread computing Fibonacci numbers with random delays. | ||
| */ | ||
| void thread_proc(); | ||
|
|
||
|
|
Uh oh!
There was an error while loading. Please reload this page.