คำถามสัมภาษณ์การซิงโครไนซ์แบบมัลติเธรด: ค้นหาคำที่ได้รับจำนวน m เธรด


23

มีวิธีใดที่ปัญหานี้จะได้รับประโยชน์จากโซลูชันที่มีหลายเธรดแทนที่จะเป็นเธรดเดี่ยวหรือไม่?


ในการสัมภาษณ์ฉันถูกขอให้แก้ปัญหาโดยใช้หลายกระทู้ สำหรับฉันแล้วดูเหมือนว่าหลายกระทู้จะไม่ให้ประโยชน์

นี่คือปัญหา:

คุณจะได้รับย่อหน้าซึ่งมีจำนวนคำ n คุณจะได้รับหัวข้อเมตร สิ่งที่คุณต้องทำคือแต่ละเธรดควรพิมพ์หนึ่งคำและให้การควบคุมกับเธรดถัดไปด้วยวิธีนี้แต่ละเธรดจะทำการพิมพ์หนึ่งคำต่อไปในกรณีที่เธรดล่าสุดมาควรเรียกเธรดแรก การพิมพ์จะทำซ้ำจนกว่าคำทั้งหมดจะถูกพิมพ์ในวรรค ในที่สุดกระทู้ทั้งหมดควรออกอย่างสง่างาม การซิงโครไนซ์ชนิดใดที่จะใช้

ฉันรู้สึกว่าเราไม่สามารถใช้ประโยชน์จากเธรดที่นี่ได้ แต่เชื่อว่าผู้สัมภาษณ์พยายามวัดทักษะการซิงโครไนซ์ของฉัน ฉันขาดอะไรบางอย่างในปัญหานี้ที่ทำให้หลายกระทู้มีค่าหรือไม่

ไม่จำเป็นต้องใช้รหัสแค่ใส่ความคิด ฉันจะดำเนินการด้วยตัวเอง


การเพิ่มแท็ก C ++ อาจไม่ช่วยได้มากนักที่นี่ คำถามนี้มีคำถามเกี่ยวกับแนวความคิดมากกว่าที่จะฟันฝ่าภาษาเฉพาะใด ๆ
cHao

เชื่อในความรู้สึกของคุณ ฉันเข้าใจสิ่งที่พวกเขากำลังทำอยู่ แต่ฉันไม่เคยชอบคำถามสัมภาษณ์ที่เบี่ยงเบนไปจากที่คุณควรจะแก้ปัญหาในโลกแห่งความจริง
G_P

16
@plusplus - ฉันจะประทับใจมากขึ้นโดยผู้ให้สัมภาษณ์ที่ชี้ให้เห็นว่าวิธีแก้ปัญหาเป็นอันดับปัญหาและเพิ่มค่าใช้จ่ายของเธรดโดยไม่ต้องดำเนินการพร้อมกัน ผู้สัมภาษณ์สามารถยืนยันว่าคุณตอบคำถามตามที่ถาม
David Harkness

ถ้า "แต่ละเธรดควรพิมพ์หนึ่งคำและให้การควบคุมกับเธรดถัดไป" ซึ่งฟังดูเหมือนงานต่อเนื่องนั่นคือหนึ่งเธรดกำลังรอให้เธรดก่อนหน้านั้นเสร็จสิ้นและเหมือนผ่านการถ่ายทอด ทำไมไม่ทำให้มันเป็นแอพพลิเคชั่นที่เป็นเธรดเดี่ยว?
สัตว์สะเทินน้ำสะเทินบก

1
ฉันเข้าใจ @Blrfl มันเหมือนกับว่าฉันต้องตรวจสอบว่าคุณรู้วิธีการใช้เครื่องมือ X แต่ขี้เกียจหรือเลอะเทอะเกินกว่าที่จะออกแบบสถานการณ์การใช้งานแอพพลิเคชั่นของแท้ที่รับประกันการใช้เครื่องมืออย่างแท้จริงดังนั้นฉันเพิ่งคว้าอะไรก็ตามมาก่อน เข้ามาอย่างสะเพร่า ตรงไปตรงมาถ้าฉันถูกถามว่าในการสัมภาษณ์ฉันจะเรียกเขาออกมาและอาจจะไม่อยากทำงานกับใครบางคนที่เลอะเทอะและ Halfast เช่นนั้น
amphibient

คำตอบ:


22

ฟังดูเหมือนว่าพวกเขากำลังนำคุณไปสู่วิธีแก้ปัญหาสัญญาณ เซมาฟอเรสใช้เพื่อส่งสัญญาณอีกครั้งว่าเป็นตาของพวกเขา พวกเขาใช้บ่อยกว่า mutexes มากซึ่งฉันเดาว่าทำไมพวกเขาถึงคิดว่าเป็นคำถามสัมภาษณ์ที่ดี นอกจากนี้ยังเป็นสาเหตุที่ทำให้ตัวอย่างดูไม่น่าเชื่อถือ

โดยทั่วไปคุณจะสร้างเซมาmฟอร์ แต่ละเธรดxรอเซมาฟอร์xแล้วโพสต์เซมาฟอร์x+1หลังจากทำสิ่งนั้น ใน pseudocode:

loop:
    wait(semaphore[x])
    if no more words:
        post(semaphore[(x+1) % m])
        exit
    print word
    increment current word pointer
    post(semaphore[(x+1) % m])

ขอบคุณสำหรับความกรุณา เอาฉันสักครู่เพื่อคิดออกว่าการวางเมาส์เหนือมันจะบอกว่าใครให้มัน
kdgregory

ขอโทษด้วยความเขลาของฉันคุณช่วยอธิบายเพิ่มเติมเกี่ยวกับวิธีการแก้ปัญหาที่ถูกต้องได้ไหม? นี่คือ semaphores แฟนซีชนิดใหม่หรือไม่? ฉันแน่ใจว่าคำถามนั้นได้รับการแก้ไขด้วยการรอ / แจ้งวิธีแก้ปัญหา
AJed

มันเป็นเพียงเซมาฟอร์มาตรฐาน ไม่มีอะไรพิเศษเกี่ยวกับพวกเขา การแจ้งเตือนเรียกว่า "โพสต์" ในการใช้งานบางอย่าง
Karl Bielefeldt

@KarlBielefeldt ถ้าทุกเธรด x รอเซมาฟอร์ x ทุกเธรดจะถูกบล็อกและจะไม่มีอะไรเกิดขึ้น หากรอ (sem) ได้รับจริง (sem) - พวกเขาจะเข้ามาในเวลาเดียวกันและไม่มีข้อยกเว้น จนกว่าจะมีการชี้แจงเพิ่มเติมฉันเชื่อว่ามีบางอย่างผิดปกติในรหัสเทียมนี้และไม่ควรเป็นคำตอบที่ดีที่สุด
AJed

นี่เป็นเพียงการแสดงลูปสำหรับแต่ละเธรด รหัสการตั้งค่าจะต้องโพสต์ไปยังเซมาฟอร์เครื่องแรกเพื่อขจัดสิ่งต่างๆ
Karl Bielefeldt

23

ในความเห็นของฉันนี่เป็นคำถามสัมภาษณ์ที่ยอดเยี่ยม - อย่างน้อยก็สมมติว่า (1) ผู้สมัครคาดว่าจะมีความรู้อย่างลึกซึ้งเกี่ยวกับการทำเกลียวและ (2) ผู้สัมภาษณ์มีความรู้อย่างลึกซึ้งและใช้คำถามเพื่อสำรวจผู้สมัคร เป็นไปได้เสมอที่ผู้สัมภาษณ์มองหาคำตอบที่เจาะจงและแคบ แต่ผู้สัมภาษณ์ที่มีความสามารถควรมองหาสิ่งต่อไปนี้:

  • ความสามารถในการแยกความแตกต่างของแนวคิดนามธรรมจากการใช้งานที่เป็นรูปธรรม ฉันโยนอันนี้ไว้เป็นหลักในการแสดงความคิดเห็นกับความคิดเห็นบางส่วน ไม่มันไม่สมเหตุสมผลเลยที่จะประมวลผลรายการคำเดียวด้วยวิธีนี้ อย่างไรก็ตามแนวคิดที่เป็นนามธรรมของขั้นตอนการปฏิบัติงานซึ่งอาจครอบคลุมความสามารถที่แตกต่างกันหลายเครื่องเป็นสิ่งสำคัญ
  • จากประสบการณ์ของฉัน (เกือบ 30 ปีของการกระจายแอพพลิเคชั่นแบบหลายขั้นตอนและแบบมัลติเธรด) การกระจายงานไม่ใช่ส่วนที่ยาก การรวบรวมผลลัพธ์และการประสานกระบวนการอิสระเป็นจุดที่เกิดข้อบกพร่องส่วนใหญ่ที่เกิดขึ้น (อีกครั้งในประสบการณ์ของฉัน) จากการกลั่นกรองปัญหาจนกลายเป็นเรื่องง่ายผู้สัมภาษณ์สามารถดูว่าผู้สมัครคิดอย่างไรเกี่ยวกับการประสานงาน นอกจากนี้ผู้สัมภาษณ์มีโอกาสถามคำถามที่ตามมาทุกประเภทเช่น "ตกลงจะเกิดอะไรขึ้นถ้าแต่ละเธรดต้องส่งคำไปยังเธรดอื่นเพื่อสร้างใหม่"
  • ผู้สมัครคิดเกี่ยวกับรูปแบบหน่วยความจำของโปรเซสเซอร์ว่ามีผลต่อการนำไปใช้งานอย่างไร หากผลลัพธ์ของการดำเนินการหนึ่งครั้งไม่เคยถูกลบออกจากแคช L1 นั่นเป็นข้อผิดพลาดแม้ว่าจะไม่มีการเกิดขึ้นพร้อมกันที่ชัดเจน
  • ผู้สมัครแยกเธรดออกจากตรรกะของแอปพลิเคชันหรือไม่

ประเด็นสุดท้ายนี้ในความคิดของฉันสำคัญที่สุด อีกครั้งตามประสบการณ์ของฉันมันเป็นเรื่องยากมากขึ้นในการดีบักโค้ดเธรดหากการผสมเธรดถูกรวมเข้ากับตรรกะของแอปพลิเคชัน ฉันเชื่อว่าโค้ดแบบมัลติเธรดที่ดีที่สุดเขียนเป็นโค้ดแบบเธรดที่มีอยู่ในตัวเองพร้อมการแฮนด์ออฟที่กำหนดไว้อย่างชัดเจน

ด้วยสิ่งนี้ในใจวิธีการของฉันจะให้แต่ละเธรดสองคิว: หนึ่งสำหรับอินพุตหนึ่งสำหรับผลลัพธ์ เธรดบล็อกในขณะที่อ่านคิวอินพุตนำคำแรกออกจากสตริงและส่งผ่านส่วนที่เหลือของสตริงไปยังเอาต์พุตคิว คุณสมบัติบางอย่างของวิธีการนี้:

  • รหัสแอปพลิเคชันรับผิดชอบการอ่านคิวทำอะไรกับข้อมูลและเขียนคิว มันไม่สนใจว่าจะเป็นแบบมัลติเธรดหรือไม่หรือไม่ว่าคิวนั้นเป็นคิวในหน่วยความจำในเครื่องหนึ่งหรือคิวที่ใช้ TCP ระหว่างเครื่องที่อยู่บนฝั่งตรงข้ามของโลก
  • เนื่องจากรหัสแอปพลิเคชันถูกเขียนราวกับว่าเธรดเดี่ยวจึงสามารถทดสอบได้ในลักษณะที่กำหนดขึ้นโดยไม่จำเป็นต้องนั่งร้านจำนวนมาก
  • ในระหว่างขั้นตอนการดำเนินการรหัสแอปพลิเคชันเป็นเจ้าของสตริงที่กำลังประมวลผล ไม่จำเป็นต้องกังวลเกี่ยวกับการซิงโครไนซ์กับเธรดที่รันพร้อมกัน

ที่กล่าวว่ายังมีพื้นที่สีเทาจำนวนมากที่ผู้สัมภาษณ์ที่มีความสามารถสามารถตรวจสอบได้:

  • "ตกลง แต่เราต้องการเห็นความรู้เกี่ยวกับการทำงานพร้อมกันคุณสามารถใช้คิวการบล็อกได้หรือไม่" แน่นอนว่าคำตอบแรกของคุณคือคุณควรใช้คิวการบล็อกที่สร้างไว้ล่วงหน้าจากแพลตฟอร์มที่คุณเลือก อย่างไรก็ตามถ้าคุณเข้าใจเธรดคุณสามารถสร้างการใช้คิวในภายใต้บรรทัดของโค้ดโหลโดยใช้สิ่งที่ซิงโครไนซ์ดั้งเดิมที่แพลตฟอร์มของคุณสนับสนุน
  • "จะเกิดอะไรขึ้นถ้าขั้นตอนเดียวในกระบวนการใช้เวลานานมาก" คุณควรพิจารณาว่าคุณต้องการคิวเอาต์พุตที่มีขอบเขตหรือไม่มีขอบเขตวิธีจัดการกับข้อผิดพลาดและผลกระทบต่อปริมาณงานโดยรวมหากคุณมีความล่าช้า
  • วิธีจัดคิวสตริงต้นฉบับอย่างมีประสิทธิภาพ ไม่จำเป็นว่าจะเป็นปัญหาหากคุณจัดการกับคิวในหน่วยความจำ แต่อาจเป็นปัญหาได้หากคุณย้ายระหว่างเครื่อง คุณอาจสำรวจ wrappers แบบอ่านอย่างเดียวที่ด้านบนของอาร์เรย์ไบต์ที่ไม่เปลี่ยนรูป

สุดท้ายถ้าคุณมีประสบการณ์ในการเขียนโปรแกรมพร้อมกันคุณอาจพูดถึงกรอบบางอย่าง (เช่น Akka สำหรับ Java / Scala) ที่ติดตามโมเดลนี้อยู่แล้ว


ข้อความทั้งหมดเกี่ยวกับแคช L1 ของโปรเซสเซอร์นั้นทำให้ฉันทึ่งจริงๆ โหวตขึ้น
Marc DiMillo

ฉันเพิ่งใช้ projectReactor กับ Spring 5 ซึ่งทำให้ฉันสามารถเขียนโค้ดผู้ไม่เชื่อเรื่องพระเจ้าได้
kundan bora

16

บางครั้งคำถามสัมภาษณ์เป็นคำถามที่หลอกลวงโดยมีจุดประสงค์เพื่อให้คุณคิดเกี่ยวกับปัญหาที่คุณพยายามแก้ไข คำถามถามเกี่ยวกับคำถามเป็นหนึ่งส่วนหนึ่งของใกล้ปัญหาไม่ว่าจะเป็นในโลกจริงหรือในการให้สัมภาษณ์ มีวิดีโอจำนวนหนึ่งหมุนเวียนอยู่บนอินเทอร์เน็ตเกี่ยวกับวิธีการตั้งคำถามในการสัมภาษณ์ทางเทคนิค (โดยเฉพาะ Google และ Microsoft)

"แค่ลองตอบคำถามแล้วออกไปจากที่นั่น .. "

การเข้าใกล้การสัมภาษณ์ด้วยรูปแบบความคิดนี้จะนำคุณไปสู่การทิ้งระเบิดการสัมภาษณ์ใด ๆ สำหรับ บริษัท ที่น่าทำงาน

หากคุณไม่คิดว่าคุณจะได้รับมาก (ถ้ามีอะไรจากการทำเกลียว) บอกพวกเขาว่า บอกพวกเขาว่าทำไมคุณไม่คิดว่ามีประโยชน์อะไร มีการสนทนากับพวกเขา การสัมภาษณ์ทางเทคนิคนั้นเป็นเวทีสนทนาที่เปิดกว้าง คุณอาจจะจบลงด้วยการเรียนรู้บางสิ่งบางอย่างเกี่ยวกับวิธีการที่จะสามารถเป็นประโยชน์ อย่าเพียง แต่เคลื่อนไปข้างหน้าโดยไม่ตั้งใจพยายามใช้สิ่งที่ผู้สัมภาษณ์บอกให้คุณทำ


3
ฉัน downvote คำตอบนี้ (แม้ว่าจะมี 4 upvotes อย่างลึกลับ) เพราะมันไม่ได้ตอบคำถามที่ถาม
Robert Harvey

1
@ RobertHarvey: บางครั้งคนก็ถามคำถามผิดๆ OP มีความคิดที่ไม่ดีในการรับมือกับการสัมภาษณ์ทางเทคนิคและคำตอบนี้เป็นความพยายามที่จะช่วยให้เขา / เธอถูกทาง
Demian Brecht

1
@ RobertHarvey ฉันเชื่อว่านี่เป็นคำตอบที่ถูกสำหรับคำถาม คำหลักที่นี่คือ "คำถามสัมภาษณ์" ซึ่งกล่าวถึงในชื่อและในเนื้อหาของคำถาม สำหรับคำถามเช่นนี้เป็นคำตอบที่ถูก หากคำถามนั้นเป็นเพียง "ฉันมีเธรด m และย่อหน้าของคำ n และฉันต้องการทำเช่นนี้และกับพวกเขาสิ่งที่เป็นวิธีที่ดีกว่า" แล้วใช่คำตอบนี้จะไม่เหมาะสมสำหรับคำถาม อย่างที่ฉันคิดว่ามันยอดเยี่ยม การถอดความ: ฉันทิ้งระเบิดคำถามสัมภาษณ์ไม่กี่เพราะฉันไม่ได้ทำตามคำแนะนำที่ได้รับที่นี่
Shivan Dragon

@RobertHarvey ตอบคำถามที่เกี่ยวข้องการลงคะแนนไม่สำเร็จอะไรเลย
Marc DiMillo

0
  • ก่อนอื่นให้โทเค็นย่อหน้าด้วยตัวคั่นที่เหมาะสมและเพิ่มคำลงในคิว

  • สร้างจำนวนเธรด N และเก็บไว้ในเธรดพูล

  • วนซ้ำเธรดพูลและเริ่มเธรดและรอให้
    เธรดเข้าร่วม และเริ่มหัวข้อถัดไปเมื่อเธรดแรกจบลงไปเรื่อย ๆ

  • แต่ละเธรดควรสำรวจความคิดเห็นคิวและพิมพ์

  • เมื่อเธรดทั้งหมดถูกใช้ภายในเธรดพูลให้เริ่มจากจุดเริ่มต้นของพูล


0

อย่างที่คุณพูดฉันไม่คิดว่าสถานการณ์นี้จะเป็นประโยชน์อย่างมากถ้าหากจากการทำเกลียว เป็นไปได้ช้ากว่าการใช้เธรดเดี่ยว

อย่างไรก็ตามคำตอบของฉันคือให้แต่ละเธรดในลูปที่พยายามเข้าถึงการล็อกซึ่งควบคุมการเข้าถึงดัชนีอาเรย์คำ แต่ละเธรดจะล็อกเอาไว้รับดัชนีรับคำที่เกี่ยวข้องจากอาร์เรย์พิมพ์เพิ่มค่าดัชนีจากนั้นจึงปลดล็อค เธรดจะออกเมื่อดัชนีอยู่ที่ท้ายอาร์เรย์

บางสิ่งเช่นนี้

while(true)
{
    lock(index)
    {
        if(index >= array.length())
          break;
        Console.WriteLine(array[index]);
        index++;
    }
}

ฉันคิดว่าสิ่งนี้ควรบรรลุเธรดหนึ่งหลังจากความต้องการอื่น แต่ไม่รับประกันการเรียงลำดับของเธรด ฉันอยากรู้วิธีแก้ปัญหาอื่น ๆ เช่นกัน


-1

ใช้เงื่อนไข wait / signal APIs เพื่อแก้ปัญหานี้

สมมติว่าเธรดแรกเลือก 1 คำและในขณะเดียวกันส่วนที่เหลือเธรดทั้งหมดกำลังรอสัญญาณ เธรดที่ 1 พิมพ์คำที่ 1 และสร้างสัญญาณไปยังเธรดถัดไปจากนั้นเธรดที่สองจะพิมพ์คำที่สองและสร้างสัญญาณไปยังเธรดที่ 3 เป็นต้นไป

#include <iostream>
#include <fstream>
#include <pthread.h>
#include <signal.h>
pthread_cond_t cond[5] = {PTHREAD_COND_INITIALIZER,};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

using namespace std;

string gstr;

void* thread1(void*)
{
    do {
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond[0],&mutex);
    cout <<"thread1 :"<<gstr<<endl;
    pthread_mutex_unlock(&mutex);
    }while(1);
}

void* thread2(void*)
{
    do{
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond[1],&mutex);
    cout <<"thread2 :"<<gstr<<endl;
    pthread_mutex_unlock(&mutex);
    }while(1);
}

void* thread3(void*)
{
    do{
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond[2],&mutex);
    cout <<"thread3 :"<<gstr<<endl;
    pthread_mutex_unlock(&mutex);
    }while(1);
}

void* thread4(void*)
{
    do{
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond[3],&mutex);
    cout <<"thread4 :"<<gstr<<endl;
    pthread_mutex_unlock(&mutex);
    }while(1);
}

void* thread5(void*)
{
    do{
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond[4],&mutex);
    cout <<"thread5 :"<<gstr<<endl;
    pthread_mutex_unlock(&mutex);
    }while(1);
}

int main()
{
    pthread_t t[5];
    void* (*fun[5])(void*);
    fun[0]=thread1;
    fun[1]=thread2;
    fun[2]=thread3;
    fun[3]=thread4;
    fun[4]=thread5;

    for (int i =0 ; i < 5; ++i)
    {
        pthread_create(&t[i],NULL,fun[i],NULL);
    }
    ifstream in;
    in.open("paragraph.txt");
    int i=0;
    while(in >> gstr)
    {

        pthread_cond_signal(&cond[i++]);
        if(i == 5)
            i=0;
        usleep(10);
    }
    for (int i =0 ; i < 5; ++i)
    {
        int ret = pthread_cancel(t[i]);
        if(ret != 0)
            perror("pthread_cancel:");
        else
            cout <<"canceled\n";
    }
    pthread_exit(NULL);
}

-1

[คำศัพท์ที่ใช้ที่นี่อาจเฉพาะสำหรับ POSIX กระทู้]

มันควรจะเป็นไปได้ที่จะใช้ mutex FIFO เช่นกันเพื่อแก้ปัญหานี้

ใช้ที่ไหน:

สมมติว่าสองเธรด T1 และ T2 กำลังพยายามเรียกใช้งานส่วนที่สำคัญ ทั้งสองไม่ต้องทำอะไรมากมายนอกส่วนที่สำคัญนี้และล็อคสายไว้เป็นเวลานาน ดังนั้น T1 อาจล็อคเรียกใช้และปลดล็อคและส่งสัญญาณ T2 สำหรับการปลุก แต่ก่อนที่ T2 จะสามารถปลุกและรับการล็อกได้ T1 จะต้องทำการล็อคและเรียกใช้งานอีกครั้ง ด้วยวิธีนี้ T2 อาจต้องรอเป็นเวลานานก่อนที่จะได้รับการล็อคจริงหรืออาจไม่ได้

มันทำงานอย่างไร / วิธีการใช้งาน:

มี mutex เพื่อล็อค เริ่มต้นข้อมูลเฉพาะของเธรด (TSD) สำหรับแต่ละเธรดไปยังโหนดที่มี id ของเธรดและเซมาฟอร์ นอกจากนี้มีสองตัวแปรที่เป็นเจ้าของ (TRUE หรือ FALSE หรือ -1), เจ้าของ (id เธรดเจ้าของ) นอกจากนี้เก็บคิวบริกรและตัวชี้บริกรล่าสุดชี้ไปที่โหนดสุดท้ายในคิวบริกร

การดำเนินการล็อค:

node = get_thread_specific_data(node_key);
lock(mutex);
    if(!owned)
    {
        owned = true;
        owner = self;
        return success;
    }

    node->next = nullptr;
    if(waiters_queue == null) waiters_queue = node;
    else waiters_last->next = node;

    waiters_last = node;
unlock(mutex);
sem_wait(node->semaphore);

lock(mutex);
    if(owned != -1) abort();
    owned = true;
    owner = self;
    waiters_queue = waiters_queue->next;
 unlock(mutex);

ปลดล็อคการดำเนินงาน:

lock(mutex);
    owner = null;
    if(waiters_queue == null)
    {
        owned = false;
        return success;
    }
    owned = -1;
    sem_post(waiters_queue->semaphore);
unlock(mutex);

-1

คำถามที่น่าสนใจ นี่คือวิธีแก้ปัญหาของฉันใน Java โดยใช้ SynchronousQueue เพื่อสร้างแชนเนลนัดพบระหว่างเธรด:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.SynchronousQueue;

public class FindNWordsGivenMThreads {

    private static final int NUMBER_OF_WORDS = 100;
    private static final int NUMBER_OF_THREADS = 5;
    private static final Stack<String> POISON_PILL = new Stack<String>();

    public static void main(String[] args) throws Exception {
        new FindNWordsGivenMThreads().run();
    }

    private void run() throws Exception {
        final Stack<String> words = loadWords();
        SynchronousQueue<Stack<String>> init = new SynchronousQueue<Stack<String>>();
        createProcessors(init);
        init.put(words);
    }

    private void createProcessors(SynchronousQueue<Stack<String>> init) {
        List<Processor> processors = new ArrayList<Processor>();

        for (int i = 0; i < NUMBER_OF_THREADS; i++) {

            SynchronousQueue in;
            SynchronousQueue out;

            if (i == 0) {
                in = init;
            } else {
                in = processors.get(i - 1).getOut();
            }

            if (i == (NUMBER_OF_THREADS - 1)) {
                out = init;
            } else {
                out = new SynchronousQueue();
            }

            Processor processor = new Processor("Thread-" + i, in, out);
            processors.add(processor);
            processor.start();

        }

    }

    class Processor extends Thread {

        private SynchronousQueue<Stack<String>> in;
        private SynchronousQueue<Stack<String>> out;

        Processor(String name, SynchronousQueue in, SynchronousQueue out) {
            super(name);
            this.in = in;
            this.out = out;
        }

        @Override
        public void run() {

            while (true) {

                Stack<String> stack = null;
                try {
                    stack = in.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if (stack.empty() || stack == POISON_PILL) {
                    System.out.println(Thread.currentThread().getName() + " Done!");
                    out.offer(POISON_PILL);
                    break;
                }

                System.out.println(Thread.currentThread().getName() + " " + stack.pop());
                out.offer(stack);
            }
        }

        public SynchronousQueue getOut() {
            return out;
        }
    }

    private Stack<String> loadWords() throws Exception {

        Stack<String> words = new Stack<String>();

        BufferedReader reader = new BufferedReader(new FileReader(new File("/usr/share/dict/words")));
        String line;
        while ((line = reader.readLine()) != null) {
            words.push(line);
            if (words.size() == NUMBER_OF_WORDS) {
                break;
            }
        }
        return words;
    }
}

-2

ฉันจะบอกว่าคำถามแบบนี้ตอบยากมากเพราะมันเป็นวิธีที่ดีที่สุดในการทำสิ่งที่โง่อย่างสมบูรณ์ สมองของฉันไม่ทำงานอย่างนั้น ไม่สามารถหาคำตอบสำหรับคำถามที่โง่ สมองของฉันจะบอกทันทีว่าภายใต้เงื่อนไขเหล่านี้การใช้หลายเธรดนั้นไม่มีประโยชน์ดังนั้นฉันจะใช้เธรดเดี่ยว

จากนั้นฉันจะขอให้พวกเขาตั้งคำถามเกี่ยวกับโลกแห่งความจริงเกี่ยวกับการทำเกลียวหรือให้ฉันยกตัวอย่างโลกแห่งความจริงของการทำเกลียวอย่างจริงจัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.