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(); }