Upgrade to PRO for Only $50/Yearโ€”Limited-Time Offer! ๐Ÿ”ฅ

Multithread design pattern

Multithread designย pattern

Avatar for Jongbin Oh

Jongbin Oh

May 09, 2022
Tweet

More Decks by Jongbin Oh

Other Decks in Programming

Transcript

  1. Single Threaded Execution ์ด ๋‹ค๋ฆฌ๋ฅผ ๊ฑด๋„ ์ˆ˜ ์žˆ๋Š” ์‚ฌ๋žŒ์€ ์˜ค์ง

    ํ•œ ๋ช… Immutable Guarded Suspension Balking Producer-Consumer Read-Write Lock Thread-Per-Message Worker Thread Future C++::Boost
  2. public class Gate { private int counter = 0; private

    String name = โ€œNobodyโ€; private String address = โ€œNowhereโ€; public void pass(String name, String address) { this.counter++; this.name = name; this.address = address; check(); } public String toString() { return โ€œNo.โ€ + counter + โ€œ: โ€œ + name + โ€œ, โ€œ + address; } private void check() { if (name.charAt(0) != address.charAt(0)) { System.out.println(โ€œ*****BROKEN*****โ€ + toString()); } } }
  3. public class UserThread extends Thread { ... public void run()

    { while(thue) { gate.pass(myname, myaddress); } } } public class Main { public static void main(String[] args) { Gate gate = new Gate(); new UserThread(gate, โ€œAliceโ€, โ€œAlaskaโ€).start(); new UserThread(gate, โ€œBobbyโ€, โ€œBrazilโ€).start(); new UserThread(gate, โ€œChrisโ€, โ€œCanadaโ€).start(); } }
  4. public class Gate { private int counter = 0; private

    String name = โ€œNobodyโ€; private String address = โ€œNowhereโ€; public void pass(String name, String address) { this.counter++; this.name = name; this.address = address; check(); } public String toString() { return โ€œNo.โ€ + counter + โ€œ: โ€œ + name + โ€œ, โ€œ + address; } private void check() { if (name.charAt(0) != address.charAt(0)) { System.out.println(โ€œ*****BROKEN*****โ€ + toString()); } } } 1. Alice ์“ฐ๋ ˆ๋“œ๊ฐ€ ์—ฌ๊ธฐ๊นŒ์ง€ ์ง„ํ–‰ 2. Bobby ์“ฐ๋ ˆ๋“œ๊ฐ€ ์—ฌ๊ธฐ๊นŒ์ง€ ์ง„ํ–‰ 3. Alice ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋‹ค์‹œ ์ง„ํ–‰ 4. name = โ€œBobbyโ€, address=โ€œAlaskaโ€
  5. public class Gate { private int counter = 0; private

    String name = โ€œNobodyโ€; private String address = โ€œNowhereโ€; public synchronized void pass( String name, String address) { this.counter++; this.name = name; this.address = address; check(); } public synchronized String toString() { return โ€œNo.โ€ + counter + โ€œ: โ€œ + name + โ€œ, โ€œ + address; } private void check() { if (name.charAt(0) != address.charAt(0)) { System.out.println(โ€œ*****BROKEN*****โ€ + toString()); } } }
  6. ์–ธ์ œ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€? ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ๋‹น์—ฐ. ์‹ฑ๊ธ€ ์“ฐ๋ ˆ๋“œ๋Š” ํ•„์š” ์—†๋‹ค. ์“ฐ๋ ˆ๋“œ

    ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ์ ‘๊ทผaccessํ•  ๋•Œ ์ƒํƒœ๊ฐ€ ๋ณ€ํ™”ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์„ ๋•Œ ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ
  7. public final class Person { private final String name; private

    final String address; public Person(String name, String address) { this.name = name; this.address = address; } public String getName() { return name; } public String getAddress() { return address; } public String toString() { return name + โ€œ , โ€œ + address; } }
  8. ์–ธ์ œ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€? ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ํ›„ ์ƒํƒœ๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š์„ ๋•Œ setter

    ๋ฉ”์†Œ๋“œ๊ฐ€ ์—†๋‹ค. ์ž์ฃผ ์ ‘๊ทผํ•˜๋Š” ๊ณต์œ  ์ธ์Šคํ„ด์Šค ์ƒํ˜ธ ๋ฐฐ์ œ๊ฐ€ ํ•„์š” ์—†๋‹ค๋Š”๊ฒŒ ์žฅ์  ๋น ๋ฅด๋‹ค๋Š” ์ด์•ผ๊ธฐ
  9. ์กฐ๋‚ธ ์ ‘๊ทผ ๋งŽ์ด ํ•ด์„œ Immutable ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€๋ฐ, Setter๊ฐ€ ์žˆ๋„ค์š”.

    ๋งํ–ˆ๋„ค์š”. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ์ฃฝ์–ด๋„ Immutable ํŒจํ„ด์„ ๋ชป ์“ฐ๋‚˜์š”?
  10. Single Threaded Execution Immutable Guarded Suspension ์ค€๋น„๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค

    ์ฃผ์„ธ์š”. Balking Producer-Consumer Read-Write Lock Thread-Per-Message Worker Thread Future C++::Boost
  11. // immutable public class Request { private final String name;

    ... public String getName() {...} public String toString() {...} } public class RequestQueue { public synchronized Request getRequest() { while (queue.peek() == null) { try { wait(); } catch (InterruptedException e) { } } return queue.remove(); } public synchronized void putRequest(Request request) { queue.offer(request); notifyAll(); } }
  12. public class ClientThread extends Thread { ... public void run()

    { while (true) { ... requestQueue.putRequest(request); } } } public class ServerThread extends Thread { ... public void run() { while (true) { Request request = requestQueue.getRequest(); ... } } }
  13. Single Threaded Execution Immutable Guarded Suspension Balking ํ•„์š” ์—†์œผ๋ฉด ๊ด€๋‘ฌ์š”

    Producer-Consumer Read-Write Lock Thread-Per-Message Worker Thread Future C++::Boost
  14. balk ์ค‘๋‹จํ•˜๊ณ  ๋Œ์•„๊ฐ€๋‹ค ์•ผ๊ตฌ๋น  : ์ƒ๊ฐํ•˜์‹œ๋Š” ๊ทธ ๋ณดํฌ ๋งž์Šต๋‹ˆ๋‹ค. ๊ฐ€๋“œ

    ์กฐ๊ฑด Guarded Suspension ํŒจํ„ด์— ๋“ฑ์žฅ ๋‹จ, ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ์ค‘๋‹จํ•œ๋‹ค.
  15. public class Data { ... public synchronized void change(String newContent)

    { content = newContent; changed = true; } public synchronized void save() { if (!changed) { return; } ... } }
  16. ์–ธ์ œ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€? ๊ตณ์ด ์ฒ˜๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๊ฐ€๋“œ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜๊ธฐ๋ฅผ

    ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์‹ถ์ง€ ์•Š์€ ๊ฒฝ์šฐ ๊ฐ€๋“œ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๊ฒƒ์ด ์ฒ˜์Œ 1ํšŒ๋ฟ์ธ ๊ฒฝ์šฐ ์˜ˆ) ์ดˆ๊ธฐํ™”
  17. Single Threaded Execution Immutable Guarded Suspension Balking Producer-Consumer ๋‚ด๊ฐ€ ๋งŒ๋“ค๊ณ 

    ๋‹น์‹ ์ด ์‚ฌ์šฉํ•œ๋‹ค. Read-Write Lock Thread-Per-Message Worker Thread Future C++::Boost
  18. producer ์ƒ์‚ฐ์ž : ๋ฐ์ดํ„ฐ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์“ฐ๋ ˆ๋“œ consumer ์†Œ๋น„์ž : ๋ฐ์ดํ„ฐ๋ฅผ

    ์ด์šฉํ•˜๋Š” ์“ฐ๋ ˆ๋“œ channel ์ƒ์‚ฐ์ž์™€ ์†Œ๋น„์ž๋ฅผ ์ด์–ด์ฃผ๋Š” ์ค‘๊ฐœ ์—ญํ• . ์ƒ์‚ฐ์ž์™€ ์†Œ๋น„์ž ์ฒ˜๋ฆฌ ์†๋„ ์ฐจ์ด๋ฅผ ๋ฉ”์šด๋‹ค. ์ƒํ˜ธ ๋ฐฐ์ œ๋Š” ์—ฌ๊ธฐ์—์„œ๋งŒ ์ˆ˜ํ–‰
  19. public class MakerThread extends Thread { ... public void run()

    { while (true) { Thread.sleep(GetRandom()); table.put(cake); } } } public class EaterThread extends Thread { ... public void run() { while (true) { String cake = table.take(); Thread.sleep(GetRandom()); } } }
  20. public class Table { ... public synchronized void put(String cake)

    { while (count >= buffer.length) { wait(); } // ์ผ€์ดํฌ๋ฅผ ๋†“๋Š”๋‹ค. notifyAll(); } public synchronized String take() { while (count <= 0) { wait(); } // ์ค„ ์ผ€์ดํฌ๋ฅผ ์ค€๋น„ notifyAll(); return cake; } }
  21. Single Threaded Execution Immutable Guarded Suspension Balking Producer-Consumer Read-Write Lock

    ๋‹ค ๊ฐ™์ด ์ฝ๋Š” ๊ฒƒ์€ ์ƒ๊ด€์—†์ง€๋งŒ ์ฝ๋Š” ์ค‘๊ฐ„์— ์“ฐ๋ฉด ์•ˆ๋ผ์š”. Thread-Per-Message Worker Thread Future C++::Boost
  22. ์ฝ๊ธฐ : ์ฝ๊ธฐ ์“ฐ๋ ˆ๋“œ ์—ฌ๋Ÿฌ๊ฐœ ์ ‘๊ทผ ๋ฌธ์ œ ์—†๋‹ค. ์“ฐ๊ธฐ :

    ์ธ์Šคํ„ด์Šค ์ƒํƒœ๊ฐ€ ๋ฐ”๋€œ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ฝ๋˜๊ฐ€ ์“ฐ๋˜๊ฐ€ ๋‹ค ๋ฌธ์ œ ์ƒ๊น€. ์ƒํ˜ธ ๋ฐฐ์ œ๋ฅผ ๋‚˜๋ˆ ์„œ ํ•˜์ž. ์ฝ๊ธฐ ์ƒํ˜ธ ๋ฐฐ์ œ ์“ฐ๊ธฐ ์ƒํ˜ธ ๋ฐฐ์ œ
  23. public class Data { ... public char[] read() { lock.readLock();

    try { return doRead(); } finally { lock.readUnlock(); } } public void write(char c) { lock.writeLock(); try { doWrite(c); } finally { lock.writeUnlock(); } } }
  24. public final class ReadWriteLock { private int readingReaders = 0;

    private int waitingWriters = 0; // ํ•œ๋ฒˆ์— ํ•œ ์“ฐ๋ ˆ๋“œ๋งŒ ์“ฐ๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๊ธฐ์ž๋ฅผ ๊ธฐ๋ก. private int writingWriters = 0; // ์ฝ๊ธฐ, ์“ฐ๊ธฐ ํ•œ์ชฝ์ด ๊ตถ์–ด ์ฃฝ๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€. private boolean preferWriter = true; public synchronized void readLock() { // ์“ฐ๊ธฐ ๋ฝ์ด ๊ฑธ๋ ธ๊ฑฐ๋‚˜ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์“ฐ๊ธฐ ๋ฝ์„ ๊ฑธ์–ด์ค˜์•ผ ํ•  ๋•Œ. while (writingWriters > 0 || (preferWriter && waitingWriters > 0)) { wait(); } readingReaders++; } public synchronized void readUnlock() { readingReaders--; preferWriter = true; notifyAll(); }
  25. public synchronized void writerLock() { waitingWriters++; try { while (readingReaders

    > 0 || writingWriters > 0) { wait(); } } finally { waitingWriters--; } writingWriters++; } public synchronized void writerUnlock() { writingWriters--; preferWriter = false; notifyAll(); } }
  26. Single Threaded Execution Immutable Guarded Suspension Balking Producer-Consumer Read-Write Lock

    Thread-Per-Message ์ด ์ผ์„ ๋ถ€ํƒํ•ด์š” Worker Thread Future C++::Boost
  27. ๋ช…๋ น์ด๋‚˜ ์š”๊ตฌ๋งˆ๋‹ค ์ƒˆ๋กœ ๋งŒ๋“  ์“ฐ๋ ˆ๋“œ ํ•œ ๊ฐœ๊ฐ€ ํ• ๋‹น ๊ทธ ์“ฐ๋ ˆ๋“œ๊ฐ€

    ์ฒ˜๋ฆฌ ์‹คํ–‰ ์ˆœ์„œ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„๋ณด์ง€ ๋ชปํ•œ๋‹ค.
  28. public class Host { public void request( final int count,

    final char c) { new Thread() { public void run() { helper.handle(count, c); } }.start(); } } public class Main { public static void Main(String[] args) { Host host = new Host(); host.request(10, โ€˜Aโ€™); host.request(20, โ€˜Bโ€™); host.request(30, โ€˜Cโ€™); } }
  29. Single Threaded Execution Immutable Guarded Suspension Balking Producer-Consumer Read-Write Lock

    Thread-Per-Message Worker Thread ์ผ์ด ์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ์ผ์ด ์˜ค๋ฉด ์ž‘์—…ํ•œ๋‹ค. Future C++::Boost
  30. ์ผ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ฌ Worker Thread ์‹ ๋‚˜๊ฒŒ

    ๊ตด๋ฆฐ๋‹ค. ์ผ์ด ์—†์„ ๋•Œ๋งŒ ์‰ฌ๊ณ  ์ผ์ด ์ฃผ์–ด์ง€๋ฉด ๋†€๊ณ  ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ฒ˜๋ฆฌ. Thread-Per-Message ํŒจํ„ด์—์„œ ์ƒˆ๋กœ์šด thread๋ฅผ ๋งค๋ฒˆ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋‹ด์„ ๋œ์–ด์ฃผ๋Š” ํŒจํ„ด Thread Pool์ด๋ผ๊ณ ๋„ ๋ถˆ๋ฆผ
  31. // ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ๋ฐ›์•„์„œ ์ „๋‹ฌ. ์›Œ์ปค ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ณด์œ . public class Channel

    { ... public void startWorkers() { for (int i = 0; i < threadPool.length; ++i) { threadPool[i].start(); } } public synchronized void putRequest(Request request) { while (count >= requestQueue.length) { wait(); } // ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ์ €์žฅ notifyAll(); } public synchronized Request takeRequest() { while (count <= 0) { wait(); } // ํ์—์„œ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ด. notifyAll(); return request; } }
  32. public class WorkerThread extends Thread { private final Channel channel;

    ... public void run() { while (true) { Request request = channel.takeRequest(); request.execute(); } } }
  33. Single Threaded Execution Immutable Guarded Suspension Balking Producer-Consumer Read-Write Lock

    Thread-Per-Message Worker Thread Future ๋จผ์ € ๊ตํ™˜๊ถŒ์„ ๋ฐ›์œผ์„ธ์š” C++::Boost
  34. Future ๋ฏธ๋ž˜ ๊ฒฝ์ œ ์šฉ์–ด) ์„ ๋ฌผ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๊ตฌํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š”

    ๋Œ€์‹ ์— ๋ฐ”๋กœ ๊ตํ™˜๊ถŒ์„ ๋ฐ›๋Š”๋‹ค. ๊ตํ™˜๊ถŒ์œผ๋กœ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์Œ. ์•„์ง ๊ฒฐ๊ณผ๊ฐ€ ์•ˆ ๋‚˜์™”๋‹ค๋ฉด ๊ธฐ๋‹ค๋ฆฐ๋‹ค. Thread-Per-Message, Worker Thread์—์„œ ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ.
  35. public class Host { public Data request(final int count, final

    char c) { final FutureData future = new FutureData(); new Thread() { public void run() { RealData realData = new RealData(count, c); future.setRealData(realData); } }.start(); return future; } }
  36. public class FutureData { ... public synchronized void setRealData( RealData

    realdata) { if (ready) { return; // balk } this.realdata = realdata; this.ready = true; notifyAll(); } public synchronized String getContent() { while (!ready) { wait(); } return realdata.getContent(); } }
  37. public class ReadData { ... public RealData(int count, char c)

    { // ์‹ค์ œ ๊ฒฐ๊ณผ๋ฌผ์„ ๊ณ„์‚ฐํ•œ๋‹ค. // ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ž‘์—… this.content = new String(buffer); } public String getContent() { return content(); } }
  38. class ReadWriteLock { public: void ReadLock() { boost::mutex::scoped_lock lock(m_mutex); {

    while (m_writingWriters > 0 || (m_preferWriter && m_waitingWriters > 0)) { m_cond.wait(lock); } m_readingReaders++; } } void ReadUnlock() { boost::mutex::scoped_lock lock(m_mutex); { m_readingReaders--; m_preferWriter = true; m_cond.notify_all(); } } ... private: boost::mutex m_mutex; boost::condition_variable m_cond; };