Skip to content

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

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 0 additions & 40 deletions Code Samples/Fib/.vscode/launch.json

This file was deleted.

48 changes: 14 additions & 34 deletions Code Samples/Fib/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -1,50 +1,30 @@
{
// 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",
"type": "shell",
"command": "make",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared"
"problemMatcher": ["$gcc"],
"options": {
"cwd": "${workspaceFolder}/Code Samples/Fib"
},
"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"
]
"detail": "Build C++ Fibonacci sample using Makefile"
},
{
"label": "clean",
"type": "shell",
"command": "make clean",
"options": {
"cwd": "${workspaceFolder}/Code Samples/Fib"
}
}
]
}

20 changes: 20 additions & 0 deletions Code Samples/Fib/Makefile
Original file line number Diff line number Diff line change
@@ -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)




2 changes: 0 additions & 2 deletions Code Samples/Fib/build.cmd

This file was deleted.

111 changes: 72 additions & 39 deletions Code Samples/Fib/main.cpp
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)));

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<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);
}
}
}
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;
}
93 changes: 53 additions & 40 deletions Code Samples/Fib/thread.cpp
Original file line number Diff line number Diff line change
@@ -1,48 +1,61 @@
#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>

// Thread-safe counter for thread IDs
static std::atomic<int> 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<int>(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<std::mutex> lock(cout_mutex);
std::cout << thread_name << ": fib(" << i << ") = " << fib(i) << std::endl;
}
std::this_thread::sleep_for(delay);
}

{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << thread_name << " exited!" << std::endl;
}
}

std::cout << thread_name << " exited!" << std::endl;
}
9 changes: 8 additions & 1 deletion Code Samples/Fib/thread.h
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();