mutex.h // MinGW 4.7 暂不支持 <mutex>,临时用这个代替
// MinGW doesn't provide <mutex> ...
#pragma once
namespace std {
struct once_flag {
bool f;
once_flag(bool f = false) : f(f) {}
};
template<typename fn_t, typename... args_t>
void call_once(once_flag& flag, fn_t fn, args_t... args) {
if(!flag.f) {
flag.f = true;
fn(args...);
}
}
}
thread.h
#pragma once
#include <windows.h>
#include <functional>
#include <stdexcept>
using namespace std;
#include "mutex.h"
typedef unsigned long ulong;
namespace threading {
struct thread;
ulong WINAPI ThreadFunc(void* thrd);
thread* get_current_thread_data();
void interruption_point();
// #define TLS_OUT_OF_INDEXES 0xFFFFFFFF
ulong current_thread_tls_key = TLS_OUT_OF_INDEXES;
struct interrupt_exception {};
struct thread_data {
bool interrupted;
typedef function<void()> f_type;
f_type _f;
thread_data() : interrupted(false) {}
template<typename F>
thread_data(F f) : _f(f), interrupted(false) {}
void run() {
if(_f) _f();
}
};
struct thread {
thread_data _data;
HANDLE _h;
ulong _id;
thread() {}
thread(thread_data data) : _data(data) {}
void start() {
_h = CreateThread(NULL, 0, ThreadFunc, (void*)this, 0, &_id);
}
void join() {
::WaitForSingleObject(_h, INFINITE);
}
void operator=(thread_data data) {
_data = data;
}
void interrupt() {
_data.interrupted = true;
}
};
std::once_flag thread_tls_once_flag;
ulong WINAPI ThreadFunc(void* thrd) {
std::call_once(thread_tls_once_flag, [&]() {
current_thread_tls_key = TlsAlloc();
});
if(current_thread_tls_key == TLS_OUT_OF_INDEXES)
throw std::runtime_error("tls alloc error");
if(!::TlsSetValue(current_thread_tls_key, thrd))
throw std::runtime_error("tls setvalue error");
try {
static_cast<thread*>(thrd)->_data.run();
} catch(interrupt_exception&) {}
return 0;
}
void interruption_point() {
thread* thrd = get_current_thread_data();
if(!thrd) throw std::runtime_error("no thread, wth");
if(thrd->_data.interrupted) {
thrd->_data.interrupted = false;
throw interrupt_exception();
}
}
thread* get_current_thread_data() {
if(current_thread_tls_key == TLS_OUT_OF_INDEXES) {
return NULL;
}
return (thread*)TlsGetValue(current_thread_tls_key);
}
}; // end of namespace thread
test:
#include <iostream>
using namespace std;
#include "../include/thread.h"
using namespace threading;
void S1() {
while(1) {
interruption_point();
cout << "S1()" << endl;
Sleep(1000);
}
}
void S2() {
while(1) {
interruption_point();
cout << "S2()" << endl;
Sleep(500);
}
}
int main() {
thread t1(S1);
thread t2;
t2 = S2;
thread t3([&]() {
Sleep(2000);
t2.interrupt();
t2.join();
Sleep(2000);
t2.start();
cout << "t3 over" << endl;
});
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
}