2012-04-14 6 views
7

मूर्खतापूर्ण मूल थ्रेडिंग अभ्यास के रूप में, मैं गोलांग में sleeping barber problem को लागू करने का प्रयास कर रहा हूं। चैनलों के साथ यह काफी आसान होना चाहिए, लेकिन मैं एक heisenbug में चला गया है। यही है, जब मैं इसका निदान करने की कोशिश करता हूं, तो समस्या गायब हो जाती है!stdout के लिए प्रिंटिंग अवरुद्ध goroutine चलाने के कारणों का कारण बनता है?

निम्नलिखित पर विचार करें। main() फ़ंक्शन shop चैनल पर पूर्णांक (या "ग्राहक") को धक्का देता है। barber() "ग्राहकों" बाल को काटने के लिए shop चैनल पढ़ता है। यदि मैं कथन customer() फ़ंक्शन में डालता हूं, तो प्रोग्राम अपेक्षित के रूप में चलता है। अन्यथा, barber() कभी भी किसी के बाल को काट नहीं देता है।

package main 

import "fmt" 

func customer(id int, shop chan<- int) { 
    // Enter shop if seats available, otherwise leave 
    // fmt.Println("Uncomment this line and the program works") 
    if len(shop) < cap(shop) { 
     shop <- id 
    } 
} 

func barber(shop <-chan int) { 
    // Cut hair of anyone who enters the shop 
    for { 
     fmt.Println("Barber cuts hair of customer", <-shop) 
    } 
} 

func main() { 
    shop := make(chan int, 5) // five seats available 
    go barber(shop) 
    for i := 0; ; i++ { 
     customer(i, shop) 
    } 
} 

कोई विचार क्या चल रहा है?

उत्तर

5

समस्या यह है कि गो का शेड्यूलर लागू किया गया है। वर्तमान goroutine केवल अन्य goroutines के लिए पैदा कर सकते हैं जब यह एक सिस्टम कॉल या एक अवरुद्ध चैनल ऑपरेशन करता है। fmt.Println एक सिस्टम कॉल करता है, जिससे गोरौटाइन को पैदा करने का मौका मिलता है। अन्यथा इसमें कोई नहीं है।

अभ्यास में यह अक्सर कोई फर्क नहीं पड़ता है, लेकिन इस तरह की छोटी समस्याओं के लिए कभी-कभी यह फसल हो सकती है।

इसके अलावा

, एक और अधिक मुहावरेदार, एक गैर अवरुद्ध एक चैनल पर भेज रहा है ऐसा करने का कम सुरम्य रास्ता: नाई की

func customer(id int, shop chan<- int) { 
    // Enter shop if seats available, otherwise leave 
    select { 
    case shop <- id: 
    default: 
    } 
} 

जिस तरह से आप कर रहे हैं, एक ग्राहक हो सकते हैं इंतज़ार कर बाहर जब तक आप वास्तव में भेजते हैं तब तक खरीदारी करें, len(shop) बदल सकता है।

+1

आपके उत्तर में यह है कि अगर रनटाइम द्वारा केवल एक थ्रेड का उपयोग किया जा रहा है। GOMAXPROCS को रनटाइम कॉल के माध्यम से या तो lazy1 कहते हैं या पर्यावरण चर सेट करने से किसी भी goroutine को अलग-अलग थ्रेड पर अन्य goroutines के समानांतर चलाने की अनुमति मिल जाएगी। उपलब्ध थ्रेड पर कैसे रनटाइम मल्टीप्लेक्स goroutines के बारे में प्रतिबिंबित करने के लिए यह आपके जवाब का विस्तार करने लायक हो सकता है। –

1

क्या मुख्य हल की शुरुआत में runtime.GOMAXPROCS(2) जोड़ना है?

+0

वास्तव में, यह करता है। यहां तक ​​कि मेरी एकल कोर मशीन पर भी ... – Jjed

+0

भले ही यह इसे ठीक करे, यह सही दृष्टिकोण नहीं है। –

+0

@MattJoiner क्या आप विस्तृत कर सकते हैं? – lazy1

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