boost::this_thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void fn() {
    try {
        while(1) {
            this_thread::interruption_point();//
            Sleep(1);
        }
    } catch(...) {}
}

thread thrd(fn);
thrd.join();


// to interrupt the thrd, call this in some other thread
//thrd.interrupt(); 

how does this_thread::interruption_point() work?
i looked into the source, it calls the get_current_thread_data() to get some data that belongs to the thread:
1
2
3
4
5
6
7
8
9
10
11
12
13
DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;

//....

        detail::thread_data_base* get_current_thread_data()
        {
            if(current_thread_tls_key==TLS_OUT_OF_INDEXES)
            {
                return 0;
            }
            return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
        }
        

now i know on win32, boost uses TLS to store the thread data, but still don't understand how the function get_current_thread_data works. It depends on current_thread_tls_key, but it seems to be a global value,
every time a thread starts, the current_thread_tls_key changes.

here's the source file:

thread.hpp: http://pastebin.com/hp5fcq5E
thread.cpp: http://pastebin.com/WqVdDcNM


Thanks.
Thread classes use a data structure (the class instance) to hold per-thread information. Strickly speaking, the use of TLS is a nicety. If thread data isn't stored in the OS's thread local storage facility, it can be held in the class, it's no big deal.

Boost is using the class to hold the TLS index. So it's using a mixture of both techniques. It's holding current_thread_tls_key in the class instance, and that just points into the OS's TLS mechanism.

As you can see, it's not necessary, and will fail if you run out of TLS slots.
how does this_thread::interruption_point() work?
It throws [unfortunately] an exception
but how this_thread::interruption_point() works, it's a global function, how could a global function knows which thread it belongs to?
for example:
1
2
3
4
5
6
void fn() {
	this_thread::interruption_point();
}

thread t_1(fn);
thread t_2(fn);

in this case, when the interruption_point() executes, how does it know whether it's in t_1 or t_2 ?
but how this_thread::interruption_point() works, it's a global function, how could a global function knows which thread it belongs to?
You can always get the id of the currently running thread. Data stored according to this id can be used to accomplish this.

It could be a simple bool in the TLS (explained by kbw) set by interrupt() and reset by interruption_point()
oh.. win32::GetCurrentThreadId
Thanks.
here's my simple implementation:)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#pragma once

#include <windows.h>
#include <functional>
using namespace std;

#include "singleton.h"

namespace thread {


struct thread;
DWORD WINAPI ThreadFunc(void* thrd);
thread* get_current_thread_data();
void interruption_point();

// #define TLS_OUT_OF_INDEXES 0xFFFFFFFF
DWORD current_thread_tls_key = TLS_OUT_OF_INDEXES;

struct tls_alloc_once : public singleton<tls_alloc_once> {
	tls_alloc_once() {
		current_thread_tls_key = TlsAlloc();
	}
};

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;
	DWORD _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;
	}
};
DWORD WINAPI ThreadFunc(void* thrd) {
	tls_alloc_once::instance();
	if(current_thread_tls_key == TLS_OUT_OF_INDEXES)
		throw std::exception("tls alloc error");

	if(!::TlsSetValue(current_thread_tls_key, thrd)) 
		throw std::exception("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::exception("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 
Topic archived. No new replies allowed.