Thread Creation Code
CPP
1. Thread class
|
1. Create Thread Object, which is entity that can start execution
immediately after creation 2. Thread object created using thread class is 2a. Not copy construtible. //error: use of deleted function 2b. Not copy assignable. //error: use of deleted function |
- Thread calling method of class
#include<thread>
class A {
void test(int a) {
cout << a;
}
public:
void fun(int a) {
//if we start thread on static function,
//then this will not be passed
thread t1(&A::test, this, a);
t1.join();
}
};
int main() {
A obj;
obj.fun(1);
}
2. Using Functor
#include <thread>
#include <iostream>
#include <mutex>
#include <vector>
std::mutex m;
void fun(int tid) {
int a;
m.lock();
a += 5;
std::cout <<
"Thread: " <<
tid << ", a:
" << a << std::endl;
m.unlock();
}
int main() {
std::vector <std::thread> vecThreads;
for (int i = 0; i< 5; ++i) {
//Functor to create Threads
vecThreads.emplace_back(
[&]() {
fun(i);
}
);
}
for (auto& t : vecThreads)
t.join();
return 0;
}
Rust
1. std::thread::spawn
-
thread::spawn() takes a
closure
as an argument, which contains the code to be executed in the new
thread
3 ways to create threads using thread::spawn
| Methods | Description |
|---|---|
| 1. Normal Closure |
|
| 2. Scoped Threads(Borrow from env) |
Normal Threads cannot borrow from their environment, but scoped
threads can. Scoped threads are not required to joined: - Reason being, when scoped thread completes, its required to return the borrowed data
|
| 3. Move Closure |
The move keyword indicates that the closure will take ownership of
any variables it captures from its environment.
|
2. std::thread::Builder
-
Allows for more control over thread creation, such as setting stack size
or naming the thread
use std::thread;
let builder = thread::Builder::new().name("my_thread".into()).stack_size(32 * 1024);
let handle = builder.spawn(|| {
println!("Hello from a custom thread!");
}).unwrap();
handle.join().unwrap();
3. Asynchronous Frameworks (e.g., Tokio)
-
For asynchronous programming, you can use libraries like Tokio, which
allows you to spawn tasks on a runtime.
#[tokio::main]
async fn main() {
tokio::spawn(async {
println!("Hello from an async task!");
});
// Other async code...
}
Go routine(Thread)
-
A goroutine is a lightweight thread of execution managed by the Go
runtime.
Goroutines run in the same address space, so access to shared memory must be synchronized
Hello World using 1 thread
package main
import (
"fmt"
"time"
)
func sayHello() {
fmt.Println("Hello from goroutine!")
}
func main() {
go sayHello() // Start a goroutine
fmt.Println("Hello from main!") // Print from the main goroutine
// Sleep for a while to allow the goroutine to execute
time.Sleep(time.Second)
}
$ go run main.go
Hello from main!
Hello from goroutine!
10 Threads executing 1 function
| Code | Description |
|---|---|
|
sync.waitgroup: - Synchronization primitive provided by the Go to synchronize the execution of a group of goroutines. - How it works? A WaitGroup maintains shared counter internally(which is initially set to 0). counter is thread-safe. At start of goroutine wg.Add(numberOfWorkers) is called. This makes counter=10 goroutine finishes (defer make wg.Done() to called after function finishes), and counter is decremented wg.Wait() method in main waits until counter=0 defer - keyword in Go schedules a function call to be executed just before the surrounding function returns. - ie wg.Done() would be called when surrounding function finishes - defer wg.Done() is called reliably, even in case of errors or unexpected goroutine termination. |
Python
import threading, zipfile
class AsyncZip(threading.Thread):
def __init__(self, infile, outfile): # Constructor
threading.Thread.__init__(self)
self.infile = infile
self.outfile = outfile
def run(self):
f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
f.write(self.infile)
f.close()
print('Finished background zip of:', self.infile)
background = AsyncZip('mydata.txt', 'myarchive.zip')
background.start()
print('The main program continues to run in foreground.')
background.join() # Wait for the background task to finish
print('Main program waited until background was done.')
POSIX
#include <pthread.h>
#include <iostream>
using namespace std;
#define NUM_OF_THREADS 5
void* worker (void* arg) {
cout << "Thread: " << *((int*)arg) << " Created";
}
int main() {
pthread_t thread_id[NUM_OF_THREADS];
int thread_args[NUM_OF_THREADS], ret;
for (int i=0;i<NUM_OF_THREADS;++i) {
thread_args[i] = i;
ret = pthread_create(&thread_id[i], 0, worker, (void*)&thread_args[i]);
}
for (int i=0; i < NUM_OF_THREADS;++i)
pthread_join (thread_id[i], 0);
return 0;
}
Java
//Class should implement Runnable Interface to create Thread
class test implements Runnable {
test() {
Thread cur = Thread.currentThread();
//1. Created child thread
Thread t = new Thread (this, "New thread");
//2. Started child thread.
//if start() is not called, Child Thread will not start
t.start();
try {
for (int i = 0; i < 6; ++i) {
//Parent process waits 1sec
System.out.println ("Parent Thread");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println ("Interrupted");
}
System.out.println ("exiting main thread");
}
public void run () {
try {
for (int i = 0; i < 3; ++i) {
//Child Thread waits 2sec
System.out.println ("Child Thread");
Thread.sleep(2000);
}
}
catch (InterruptedException e) {
System.out.println ("child interrupted");
}
System.out.println ("exiting child thread");
}
public static void main (String args[]) {
new test(); //1. Calls constructor
}
}
$ javac test.java
$ java test
$ java test
Parent Thread
Child Thread
Parent Thread
Child Thread
Parent Thread
Parent Thread
Child Thread
Parent Thread
Parent Thread
exiting child thread
exiting main thread
Windows
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
using namespace std;
DWORD WINAPI worker(LPVOID param) {
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
int* data = (int*)param;
TCHAR buf[60];
DWORD dwChar;
StringCchPrintf(buf, 60, TEXT("val=%d"), *data);
WriteConsole(hStdout, buf, 10, &dwChar, nullptr);
return 0;
}
int _tmain() {
DWORD thread_id[5];
for (int i = 0; i < 5; ++i) {
CreateThread(
NULL, //Default security attributes
0, //Use default stack size
worker, //thread function
(void*)i, //argument to thread function
0, //Default creation flag
&thread_id[i]); //Thread identifier returned
}
}