2009-11-18 39 views
42

खोजा गया, लेकिन एक संतोषजनक उत्तर में न आएं।कैसे मुद्रित करें pthread_t

मुझे पता है कि pthread_t मुद्रित करने के लिए कोई पोर्टेबल तरीका नहीं है।

आप इसे अपने ऐप में कैसे करते हैं?

अद्यतन:

असल में मैं डिबग संदेश अलग धागे में पहचान करने pthread_t की जरूरत नहीं है, लेकिन कुछ छोटे सांख्यिक आईडी,।

मेरे सिस्टम (64 बिट आरएचईएल 5.3) पर इसे बिना हस्ताक्षर किए गए लंबे int के रूप में परिभाषित किया गया है, इसलिए यह बड़ी संख्या है और प्रिंटिंग यह डीबग लाइन में एक मूल्यवान जगह खाती है। gdb कैसे संक्षिप्त बोलियां असाइन करता है?

उत्तर

28

यह एक pthread_t की एक हेक्साडेसिमल प्रतिनिधित्व बाहर प्रिंट होगा, कोई फर्क नहीं पड़ता कि क्या वास्तव में है:

void fprintPt(FILE *f, pthread_t pt) { 
    unsigned char *ptc = (unsigned char*)(void*)(&pt); 
    fprintf(f, "0x"); 
    for (size_t i=0; i<sizeof(pt); i++) { 
    fprintf(f, "%02x", (unsigned)(ptc[i])); 
    } 
} 

सिर्फ एक छोटे से प्रिंट करने के लिए प्रत्येक pthread_t के लिए आईडी का उपयोग इस तरह किया जा सकता है (इस बार iostreams का उपयोग कर):

void printPt(std::ostream &strm, pthread_t pt) { 
    static int nextindex = 0; 
    static std::map<pthread_t, int> ids; 
    if (ids.find(pt) == ids.end()) { 
    ids[pt] = nextindex++; 
    } 
    strm << ids[pt]; 
} 

मंच और pthread_t की वास्तविक प्रतिनिधित्व इसे यहाँ क्योंकि std::map तत्वों पर एक आदेश देने की जरूरत है, एक pthread_t के लिए operator< परिभाषित करने के लिए आवश्यक हो सकता है पर निर्भर करता है:

bool operator<(const pthread_t &left, const pthread_t &right) { 
    ... 
} 
+0

+1। लेकिन यह समाधान अब तक pthread_t प्रतिनिधित्व उत्पन्न करता है कि यह संख्यात्मक "गैर पोर्टेबल" समाधान है। – dimba

+0

gdb एक छोटी संख्या असाइन करता है। मैं कुछ समान समाधान – dimba

+1

आर पेट से खुश हूं: नहीं, ऐसा नहीं है। ध्यान दें कि 'ptc' सूचक को 'fprintf' पंक्ति में संदर्भित किया गया है। – caf

14

इस मामले में, यह ऑपरेटिंग सिस्टम पर निर्भर करता है, the POSIX standard no longer requires pthread_t to be an arithmetic type के बाद से:

IEEE Std 1,003.1-2001/कोर 2-2004, आइटम XBD/TC2/D6/26 लागू किया जाता है, के लिए pthread_t जोड़ने उन प्रकारों की सूची जिन्हें अंकगणितीय प्रकार की आवश्यकता नहीं है, इस प्रकार pthread_t को संरचना के रूप में परिभाषित करने की अनुमति है।

आपको अपने sys/types.h शीर्षलेख में देखने की आवश्यकता होगी और देखें कि pthread_t लागू किया गया है; तो आप इसे प्रिंट कर सकते हैं कि आप कैसे फिट देखते हैं। चूंकि ऐसा करने का कोई पोर्टेबल तरीका नहीं है और आप यह नहीं कहते कि आप किस ऑपरेटिंग सिस्टम का उपयोग कर रहे हैं, वहां कहने के लिए बहुत कुछ नहीं है।

संपादित करें: अपने नए सवाल, GDB assigns its own thread ids each time a new thread starts जवाब देने के लिए:

डीबगिंग उद्देश्यों के लिए, gdb एक भी पूर्णांक के साथ अपने कार्यक्रम में प्रत्येक थ्रेड एकत्रित करती है अपनी ही धागा संख्या-हमेशा।

यदि आप प्रत्येक धागे के अंदर एक अनूठी संख्या छपाई को देख रहे हैं, तो आपका सबसे साफ विकल्प शायद प्रत्येक धागे को बताना होगा कि जब आप इसे शुरू करते हैं तो किस नंबर का उपयोग करना है।

+0

एक धागा-स्थानीय भंडारण चर भी काम करेगा। आप किसी दिए गए धागे के लिए आवश्यक होने तक संख्या निर्दिष्ट करने पर रोक लगा सकते हैं, लेकिन यह आपके कार्यक्रम के लिए विशिष्ट ट्रेडऑफ में हो रहा है। –

+0

जेम्स: "आपका सबसे साफ विकल्प शायद प्रत्येक थ्रेड को बताना होगा कि जब आप इसे शुरू करते हैं तो किस नंबर का उपयोग करना है" - मैं बस 'pthread_create' के माध्यम से wen, और कुछ भी मुझ पर कूद गया। कोई इसे कैसे करता है? – jww

+0

'pthread_create' के चौथे पैरामीटर आपको थ्रेड प्रक्रिया में मनमाना डेटा पास करने की अनुमति देता है। पोर्टेबिलिटी के लिए –

4

केंद्रों पर 5.4 x86_64, pthread_t एक हस्ताक्षरित लंबे समय तक टाइप किया गया है।

इसलिए, हम ऐसा कर सकता है ...

#include <iostream> 
#include <pthread.h> 

int main() { 
    pthread_t x; 
    printf("%li\n", (unsigned long int) x); 
    std::cout << (unsigned long int) x << "\n"; 
} 
7

ठीक है, लगता है यह मेरा अंतिम जवाब है।हमारे पास 2 वास्तविक समस्याएं हैं:

  • लॉगिंग के लिए थ्रेड के लिए छोटे अद्वितीय आईडी कैसे प्राप्त करें।
  • वैसे भी हमें थ्रेड के लिए वास्तविक pthread_t आईडी मुद्रित करने की आवश्यकता है (केवल कम से कम POSIX मानों से लिंक करने के लिए)।

1. प्रिंट POSIX आईडी (pthread_t)

आप बस प्रत्येक बाइट के लिए मुद्रित हेक्स अंक के साथ बाइट्स की सरणी के रूप में pthread_t इलाज कर सकते हैं। तो आप कुछ निश्चित आकार के प्रकार से सीमित नहीं हैं। एकमात्र मुद्दा बाइट ऑर्डर है। आपको शायद यह पसंद है कि आपके मुद्रित बाइट्स का क्रम सरल "int" मुद्रित जैसा ही है। यहाँ बड़े endian के लिए (परिभाषित के तहत?) थोड़ा-endian और केवल आदेश वापस लाए जाने चाहिए के लिए उदाहरण है:

#include <pthread.h> 
#include <stdio.h> 

void print_thread_id(pthread_t id) 
{ 
    size_t i; 
    for (i = sizeof(i); i; --i) 
     printf("%02x", *(((unsigned char*) &id) + i - 1)); 
} 

int main() 
{ 
    pthread_t id = pthread_self(); 

    printf("%08x\n", id); 
    print_thread_id(id); 

    return 0; 
} 

2. कम प्रिंट करने योग्य थ्रेड ID

जाओ प्रस्तावित से किसी भी मामले में आप चाहिए कुछ तालिका के सूचकांक के लिए वास्तविक धागा आईडी (posix) का अनुवाद करें। लेकिन 2 महत्वपूर्ण भिन्न दृष्टिकोण हैं:

2.1। ट्रैक धागे।

आप तालिका में मौजूद सभी मौजूदा धागे की थ्रेड आईडी ट्रैक कर सकते हैं (उनके pthread_create() कॉल को लपेटा जाना चाहिए) और "ओवरलोडेड" आईडी फ़ंक्शन है जो आपको केवल टेबल इंडेक्स प्राप्त करता है, असली थ्रेड आईडी नहीं। यह योजना संसाधन ट्रैकिंग को किसी भी आंतरिक थ्रेड से संबंधित डीबग के लिए भी बहुत उपयोगी है। स्पष्ट लाभ भविष्य के विस्तार के साथ थ्रेड-स्तरीय ट्रेस/डीबग सुविधा का दुष्प्रभाव है। किसी भी थ्रेड निर्माण/विनाश को ट्रैक करने के लिए नुकसान की आवश्यकता है।

pthread_create_wrapper(...) 
{ 
    id = pthread_create(...) 
    add_thread(id); 
} 

pthread_destruction_wrapper() 
{ 
    /* Main problem is it should be called. 
     pthread_cleanup_*() calls are possible solution. */ 
    remove_thread(pthread_self()); 
} 

unsigned thread_id(pthread_t known_pthread_id) 
{ 
    return seatch_thread_index(known_pthread_id); 
} 

/* user code */ 
printf("04x", thread_id(pthread_self())); 

2,2:

यहाँ आंशिक स्यूडोकोड उदाहरण है। बस नई धागा आईडी पंजीकृत करें।

लॉगिंग के दौरान pthread_self() कॉल करें और अगर यह थ्रेड पता है तो आंतरिक तालिका खोजें। यदि ऐसी आईडी के साथ धागा बनाया गया था तो इसकी अनुक्रमणिका का उपयोग किया जाता है (या पहले थ्रेड से पुनः उपयोग किया जाता है, वास्तव में इससे कोई फर्क नहीं पड़ता क्योंकि एक ही पल के लिए 2 समान आईडी नहीं हैं)। यदि थ्रेड आईडी अभी तक ज्ञात नहीं है, तो नई प्रविष्टि बनाई गई है इसलिए नई अनुक्रमणिका जेनरेट/प्रयुक्त होती है।

लाभ सादगी है। नुकसान धागा निर्माण/विनाश की कोई ट्रैकिंग नहीं है। तो इसे ट्रैक करने के लिए कुछ बाहरी यांत्रिकी आवश्यक है।

+0

+1। मैं भी इस दृष्टिकोण पर विचार कर रहा था। हालांकि मेरे पास सभी बनाए गए धागे पर नियंत्रण नहीं है, लेकिन वे सभी एक ही फ़ंक्शन का उपयोग लॉगर में संदेश प्रिंट करने के लिए करते हैं। तो मैं लॉग समय पर एक लुकअप टेबल बना सकता हूं। – dimba

22

जीडीबी लिनक्स पर छोटी संख्या के लिए थ्रेड-आईडी (उर्फ कर्नेल पिड, उर्फ ​​एलडब्ल्यूपी) का उपयोग करता है। आज़माएं:

#include <syscall.h> 
    ... 

    printf("tid = %d\n", syscall(SYS_gettid)); 
+0

यह एलडब्ल्यूपी देता है। हो सकता है कि मैं गलत हूं लेकिन अलग-अलग एलडब्ल्यूपी के लिए रनटाइम पर पैथ्रेड को बाध्य किया जा सकता है, इस प्रकार अलग-अलग pthreads – dimba

+4

विशिष्ट रूप से पहचान नहीं है लिनक्स पर pthread_t और LWP के बीच 1: 1 मैपिंग है।आप अपने जीवनकाल में अलग-अलग बिंदुओं पर अलग-अलग एलडब्ल्यूपी की रिपोर्ट करने के लिए कभी भी एक ही थ्रेड नहीं प्राप्त करेंगे। –

+0

इसे एलडब्लूपी कॉल करना आईएमओ लिनक्स पर गलत है। क्योंकि कोई "हल्का" और "भारी" वजन प्रक्रिया नहीं है। केवल _tasks_ हैं, शेड्यूल करने योग्य इकाइयां, जो विभिन्न संसाधनों को साझा कर सकती हैं। और यही वह लिनक्स-विशिष्ट सिस्टम कॉल रिटर्न, _task_ आईडी है। –

1

आप इसे बिना किसी हस्ताक्षरित शॉर्ट में परिवर्तित करने का प्रयास कर सकते हैं और फिर अंतिम चार हेक्स अंकों को प्रिंट कर सकते हैं। परिणामस्वरूप मूल्य आपकी आवश्यकताओं के लिए पर्याप्त अद्वितीय हो सकता है।

+0

के साथ चेतावनियों से बचने के लिए% lu का उपयोग करें मैं कैसे सुनिश्चित कर सकता हूं कि यह 2 बाइट सभी थ्रेड आईडी पर अद्वितीय हैं? – dimba

+0

मैंने कहा कि यह * अद्वितीय * हो सकता है। आप हमेशा अंतिम * एन * अंकों पर छंटनी कर सकते हैं, जहां * एन * प्रयोगात्मक रूप से निर्धारित किया जाता है। –

3

आप कुछ इस तरह कर सकता है:

int thread_counter = 0; 

static void *threadproc(void *data) { 
    int thread_id = __sync_add_and_fetch(&thread_counter, 1); 
    printf("Thread %d reporting for duty!\n", thread_id); 
    return NULL; 
} 

अपने मंच हैं:

int thread_counter = 0; 
pthread_mutex_t thread_counter_lock = PTHREAD_MUTEX_INITIALIZER; 

int new_thread_id() { 
    int rv; 
    pthread_mutex_lock(&thread_counter_lock); 
    rv = ++thread_counter; 
    pthread_mutex_unlock(&thread_counter_lock); 
    return rv; 
} 

static void *threadproc(void *data) { 
    int thread_id = new_thread_id(); 
    printf("Thread %d reporting for duty!\n", thread_id); 
    return NULL; 
} 

आप जीसीसी होने पर भरोसा कर सकते हैं (बजना भी इस मामले में काम करता है), तो आप भी ऐसा कर सकते हैं इसका समर्थन करता है, एक समान विकल्प:

int thread_counter = 0; 
int __thread thread_id = 0; 

static void *threadproc(void *data) { 
    thread_id = __sync_add_and_fetch(&thread_counter, 1); 
    printf("Thread %d reporting for duty!\n", thread_id); 
    return NULL; 
} 

यह लाभ है कि आपको थ्रेस के आसपास पास नहीं करना है फ़ंक्शन कॉल में d_id, लेकिन यह काम नहीं करता है उदा। मैक ओएस पर

3

यदि pthread_t केवल एक संख्या है; यह सबसे आसान होगा।

int get_tid(pthread_t tid) 
{ 
    assert_fatal(sizeof(int) >= sizeof(pthread_t)); 

    int * threadid = (int *) (void *) &tid; 
    return *threadid; 
} 
2

एक लुकअप तालिका (pthread_t : int) प्रोग्राम हैं जो अल्पकालिक धागे का एक बहुत शुरू में एक स्मृति रिसाव हो सकता है।

pthread_t (चाहे वह संरचना या सूचक या लंबा पूर्णांक या जो भी हो) के बाइट्स का हैश बनाना एक उपयोगी समाधान हो सकता है जिसे लुकअप टेबल की आवश्यकता नहीं होती है। किसी भी हैश के साथ टकराव का खतरा होता है, लेकिन आप अपनी आवश्यकताओं के अनुसार हैश की लंबाई को ट्यून कर सकते हैं।

+0

क्या होगा यदि प्रत्येक थ्रेड में एक से अधिक संभव 'pthread_t' मान है जो इसका संदर्भ देता है? –

1

मुझे पता है, यह धागा बहुत पुराना है। सभी उपरोक्त पदों को पढ़ने के बाद, मैं इसे एक साफ तरीके से संभालने के लिए एक और विचार जोड़ना चाहता हूं: यदि आप मैपिंग व्यवसाय में किसी भी तरह से मैपिंग करते हैं (pthread_to को int में मैप करना), तो आप पठनीयता में एक कदम आगे भी जा सकते हैं। अपने pthread_create_wrapper को इस तरह बनाएं कि यह एक स्ट्रिंग भी लेता है ... थ्रेड का नाम। मैंने विंडोज़ और विंडोज सीई पर इस "SetThreadName()" सुविधा की सराहना करना सीखा। लाभ: आपकी आईडी केवल संख्याएं नहीं हैं बल्कि आप यह भी देखते हैं कि आपके धागे का कौन सा उद्देश्य है।

0

बस पहली पोस्ट के लिए एक पूरक: pthread_t स्टोर करने के लिए एक उपयोगकर्ता परिभाषित संघ प्रकार का उपयोग करें:

union tid { 
    pthread_t pthread_id; 
    unsigned long converted_id; 
}; 

जब भी आप pthread_t प्रिंट करना चाहते हैं, एक tid बना सकते हैं और tid.pthread_id = ... दें और इसके बाद tid.converted_id मुद्रित करें।

+2

कोई गारंटी नहीं है कि यह प्रत्येक थ्रेड के लिए एक अद्वितीय मूल्य उत्पन्न करेगा। वास्तव में, यह विशेष रूप से क्यों है कि हमारे पास 'pthread_equal' जैसे कार्य हैं। –

संबंधित मुद्दे