Bonita Montero
2020-12-06 09:37:18 UTC
Unter Windows wird im x86-Modus das FS-Register als Basis des Thread
-Information-Blocks verwendet. Da findet sich z.B. die global eindeu-
tige Thread-ID, die Stack-Boundaries u.s.w. ([*]). Ich benutze das
in einem eigenen Mutex, dass einen Schreiber oder mehrere Leser mit
Priorität des Schreibers erlaubt um den Schreiber-Zustand rekursiv
zu machen (wenn Schreiber && Schreiber-Thread-ID == aktuelle Thread
-id ...).
Aktuell habe ich eine kleine Thread-ID-Klasse, und die sieht so aus:
#pragma once
#if defined(_MSC_VER)
#include <Windows.h>
#include <intrin.h>
#elif defined(__unix__)
#include <pthread.h>
#endif
struct thread_id
{
thread_id();
thread_id &operator =( thread_id const &other );
bool operator ==( thread_id const &other );
thread_id &to_self();
static
thread_id self();
private:
#if defined(_MSC_VER)
DWORD m_dwThreadId;
#elif defined(__unix__)
bool m_set;
int m_threadId;
#else
#error "unsupported platform for thread_id"
#endif
};
inline
thread_id::thread_id()
{
#if defined(_MSC_VER)
m_dwThreadId = 0;
#elif defined(__unix__)
m_set = false;
#endif
}
inline
thread_id &thread_id::operator =( thread_id const &other )
{
#if defined(_MSC_VER)
m_dwThreadId = other.m_dwThreadId;
#elif defined(__unix__)
m_set = other.m_set;
m_threadId = other.m_threadId;
#endif
return *this;
}
inline
bool thread_id::operator ==( thread_id const &other )
{
#if defined(_MSC_VER)
return m_dwThreadId == other.m_dwThreadId;
#elif defined(__unix__)
return m_set && other.m_set && m_threadId == other.m_threadId;
#endif
}
inline
thread_id &thread_id::to_self()
{
thread_id tid;
#if defined(_MSC_VER)
#if defined(_M_X64)
m_dwThreadId = __readgsdword( 0x30 );
#elif defined(_M_IX86)
m_dwThreadId = __readfsdword( 0x18 );
#else
#error "not supported Windows-platform"
#endif
#elif defined(__unix__)
m_set = true;
m_threadId = pthread_self();
#endif
return *this;
}
inline
thread_id thread_id::self()
{
thread_id tid;
return tid.to_self();
}
Wie man sieht benutze ich unter Windows spezielle Intrinsics um die
Thread-ID aus dem TIB auszulesen. Das ist ca. fünfmal Schneller als
ein Aufruf von GetThreadId(). Etwas analoges wünsche ich mir auch
unter Linux.
Jetzt habe ich zwei Fragen:
1. gibt es unter Linux auch so eine Thead-ID in etwas analogem zum
Thread-Information-Block ?
2. Wenn nicht, dann muss ich wohl obigen Code ungefähr weiterverwenden.
Kann ich mir ggf. m_set ersparen und für m_Set == false eine reser-
vierte Thread-ID setzen bzw. ist vielleicht eine Thread-ID von Null
reserviert ? Mir würde ggf. sogar eine Aussage mit der Einschränkung
auf Linux reichen, denn auf anderen Unix-Plattformen soll mein Code
eh nicht laufen.
[*] https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
-Information-Blocks verwendet. Da findet sich z.B. die global eindeu-
tige Thread-ID, die Stack-Boundaries u.s.w. ([*]). Ich benutze das
in einem eigenen Mutex, dass einen Schreiber oder mehrere Leser mit
Priorität des Schreibers erlaubt um den Schreiber-Zustand rekursiv
zu machen (wenn Schreiber && Schreiber-Thread-ID == aktuelle Thread
-id ...).
Aktuell habe ich eine kleine Thread-ID-Klasse, und die sieht so aus:
#pragma once
#if defined(_MSC_VER)
#include <Windows.h>
#include <intrin.h>
#elif defined(__unix__)
#include <pthread.h>
#endif
struct thread_id
{
thread_id();
thread_id &operator =( thread_id const &other );
bool operator ==( thread_id const &other );
thread_id &to_self();
static
thread_id self();
private:
#if defined(_MSC_VER)
DWORD m_dwThreadId;
#elif defined(__unix__)
bool m_set;
int m_threadId;
#else
#error "unsupported platform for thread_id"
#endif
};
inline
thread_id::thread_id()
{
#if defined(_MSC_VER)
m_dwThreadId = 0;
#elif defined(__unix__)
m_set = false;
#endif
}
inline
thread_id &thread_id::operator =( thread_id const &other )
{
#if defined(_MSC_VER)
m_dwThreadId = other.m_dwThreadId;
#elif defined(__unix__)
m_set = other.m_set;
m_threadId = other.m_threadId;
#endif
return *this;
}
inline
bool thread_id::operator ==( thread_id const &other )
{
#if defined(_MSC_VER)
return m_dwThreadId == other.m_dwThreadId;
#elif defined(__unix__)
return m_set && other.m_set && m_threadId == other.m_threadId;
#endif
}
inline
thread_id &thread_id::to_self()
{
thread_id tid;
#if defined(_MSC_VER)
#if defined(_M_X64)
m_dwThreadId = __readgsdword( 0x30 );
#elif defined(_M_IX86)
m_dwThreadId = __readfsdword( 0x18 );
#else
#error "not supported Windows-platform"
#endif
#elif defined(__unix__)
m_set = true;
m_threadId = pthread_self();
#endif
return *this;
}
inline
thread_id thread_id::self()
{
thread_id tid;
return tid.to_self();
}
Wie man sieht benutze ich unter Windows spezielle Intrinsics um die
Thread-ID aus dem TIB auszulesen. Das ist ca. fünfmal Schneller als
ein Aufruf von GetThreadId(). Etwas analoges wünsche ich mir auch
unter Linux.
Jetzt habe ich zwei Fragen:
1. gibt es unter Linux auch so eine Thead-ID in etwas analogem zum
Thread-Information-Block ?
2. Wenn nicht, dann muss ich wohl obigen Code ungefähr weiterverwenden.
Kann ich mir ggf. m_set ersparen und für m_Set == false eine reser-
vierte Thread-ID setzen bzw. ist vielleicht eine Thread-ID von Null
reserviert ? Mir würde ggf. sogar eine Aussage mit der Einschränkung
auf Linux reichen, denn auf anderen Unix-Plattformen soll mein Code
eh nicht laufen.
[*] https://en.wikipedia.org/wiki/Win32_Thread_Information_Block