반응형

메시지 박스

메시지 상자는 별도의 다이얼로그에 메시지를 표시하는 데 사용됩니다. 메시지 상자를 표시하려면 showinfo() 메서드를 호출하면 됩니다. 메시지 상자를 통해 표시하려는 메시지는 메시지 속성에 전달됩니다.

 

다음 스크립트에서는 기본 다이얼로그에 버튼 위젯을 추가합니다. 버튼을 클릭하면 메시지 상자에 버튼을 클릭했습니다.라는 메시지가 표시됩니다.

 

from tkinter import *

from tkinter import ttk

 

# importing showinfor message box

from tkinter.messagebox import showinfo

  

# creating instance of Tk class

main_window = Tk()

 

# setting window dimensions

main_window.geometry("500x500+100+200")

 

def my_func():

    # creating a message box

    showinfo(title = "Information", message = "You clicked a button")

       

# creating a themed button

my_button = ttk.Button(main_window, text = "Click here", command = my_func)

 

# attacing themed button to main window

my_button.pack(fill='x', expand=True)

 

# displaying the main window

main_window.mainloop()

 

Output:

 

여러위젯 추가

다이얼로그에 여러 위젯을 추가할 수도 있습니다. 과정은 간단합니다. 각 위젯 클래스에 대한 객체를 생성해야 합니다.

다음으로 위젯을 연결할 다이얼로그를 첫 번째 매개변수로 전달해야 합니다. 마지막으로 각 위젯 클래스 객체를 사용하여 pack() 메서드를 호출해야 합니다.

 

다음 스크립트에서는 기본 창에 간단한 레이블 위젯과 테마가 있는 버튼 위젯을 추가합니다. 버튼을 클릭하면 콘솔에 메시지가 표시됩니다.

 

from tkinter import *

from tkinter import ttk

 

# defining the callback function

def my_func():

    print("a button is clicked")

   

# creating instance of Tk class

main_window = Tk()

 

# setting window dimensions

main_window.geometry("500x500+100+200")

 

# creating the default label

my_label= Label(main_window, text = "Welcome to Python")

 

# attaching default label to main window

my_label.pack()

 

# creating a themed button

my_button = ttk.Button(main_window, text ="Click here", command = my_func)

 

# attaching themed button to main window

my_button.pack()

 

main_window.mainloop()

 

Output:

 

마찬가지로 다음 스크립트는 기본 다이얼로그에 일반 레이블 위젯, 테마 레이블 위젯 및 테마 버튼을 추가합니다. 버튼을 클릭하면 콘솔에 메시지가 표시됩니다.

 

from tkinter import *

from tkinter import ttk

 

# defining the callback function

def my_func():

    print("a button is clicked")

   

# creating instance of Tk class

main_window = Tk()

 

# setting window dimensions

main_window.geometry("500x500+100+200")

 

# creating the default label

my_label= Label(main_window, text = "Welcome to Python")

 

# attaching default label to main window

my_label.pack()

 

# creating a themed label

my_label2 = ttk.Label(main_window, text ="Welcome to Python2")

 

# attaching themed label to main window

my_label2.pack()

 

# creating a themed button

my_button = ttk.Button(main_window, text ="Click here", command = my_func)

 

# attaching themed button to main window

my_button.pack()

 

main_window.mainloop()

 

Output:

 

아래 스크립트는 테마 항목과 테마 버튼 위젯을 메인 창에 추가합니다. 버튼을 클릭하면 Entry 위젯에서 정의한 텍스트 필드에 입력한 텍스트가 메시지 상자에 표시됩니다.

 

from tkinter import *

from tkinter import ttk

  

# creating instance of Tk class

main_window = Tk()

 

# setting window dimensions

main_window.geometry("500x500+100+200")

 

# creating variable that contains text from the text field

my_text=StringVar()

 

# creating a text field using Entry class

text_field=ttk.Entry(main_window,textvariable=my_text)

 

# addding the text field to the main window

text_field.pack(fill='x', expand=True)

 

def my_func():

    text = ""

    if my_text.get() == "":

        text = "Enter something in the text box"

    else:

        text = "You entered:" + my_text.get()

       

    # creating a message box

    showinfo(title = "Information", message = text)

       

# creating a themed button

my_button = ttk.Button(main_window, text = "Click here", command = my_func)

 

# attacing themed button to main window

my_button.pack(fill='x', expand=True)

 

# displaying the main window

main_window.mainloop()

 

Output:

 

Layout 생성

레이아웃을 사용하면 특정 방식으로 위젯을 구성할 수 있습니다.

다음 스크립트는 2개의 행과 3개의 열이 있는 그리드 레이아웃을 만듭니다.

그리드 레이아웃을 생성하려면 Tk 클래스 객체의 columnconfigure() 메서드를 통해 각 열의 위치와 너비를 정의하기만 하면 됩니다.

 

columnconfigure()의 첫 번째 매개변수 값은 열 위치입니다. 첫 번째 열 위치는 0이어야 합니다. 열 범위에 해당하는 가중치 매개변수 값을 지정할 수도 있습니다.

 

예를 들어 다음 스크립트에서는 가중치가 1인 열 세 개를 만듭니다. 열의 가중치를 2로 설정하면 해당 열의 너비는 가중치가 1인 열 너비의 두 배가 됩니다.

행에 대한 값을 지정할 필요가 없습니다. 위젯을 메인 창에 연결하면 행이 자동으로 추가됩니다. 위젯을 기본 창에 연결하려면 grid() 메서드를 호출하고 위젯을 배치할 행 및 열 인덱스의 위치를 ​​전달해야 합니다.

행 인덱스는 위젯의 행 속성을 통해 지정됩니다.

마찬가지로 열 인덱스는 열 속성을 통해 지정됩니다. 행 및 열 인덱스는 0부터 시작합니다. 예를 들어 행 및 열 값이 0이면 위젯이 첫 번째 행과 첫 번째 열에 배치됩니다.

 

다음 스크립트는 기본 창에 두 개의 레이블을 추가합니다. 첫 번째 레이블은 첫 번째 행과 첫 번째 열 인덱스에 위치합니다.

두 번째 레이블은 첫 번째 행과 두 번째 열에 있습니다.

 

다음 스크립트는 기본 창에 두 개의 버튼도 추가합니다. 첫 번째 버튼은 첫 번째 행과 세 번째 열에 있습니다. 두 번째 버튼은 두 번째 행과 첫 번째 열에 배치됩니다. 두 번째 Button 위젯 개체, my_button2를 통해 grid() 메서드를 호출할 때 columnspan 속성에 값 3을 전달합니다. columnspan 속성은 위젯이 사용할 범위의 수를 정의합니다. columnspan 3이면 행 및 열 인덱스에서 셀의 위치를 ​​지정하고 해당 범위를 3개의 열로 늘립니다.

 

from tkinter import *

from tkinter import ttk

 

# creating instance of Tk class

main_window = Tk()

 

# setting window dimensions

main_window.geometry("500x500+100+200")

 

# configure the grid

main_window.columnconfigure(0, weight = 1)

main_window.columnconfigure(1, weight = 1)

main_window.columnconfigure(2, weight = 1)

 

# creating the default label

my_label= Label(main_window, text = "Welcome to Python")

 

# attaching label to first row and first column

my_label.grid(column = 0, row = 0, padx = 5, pady = 5)

 

# creating a themed label

my_label2 = ttk.Label(main_window, text = "Welcome to Python2")

 

# attaching label to first row and second column

my_label2.grid(column = 1, row = 0, padx = 5, pady = 5)

 

 

# creating a themed button

my_button = ttk.Button(main_window, text ="Click here")

 

# attaching a button to first row and third column

my_button.grid(column = 2, row = 0, padx = 5, pady = 5)

 

# creating a themed button

my_button2 = ttk.Button(main_window, text ="This button spans three columns and will be centered horizontally")

 

# attaching a button to first row and third column

my_button2.grid(column = 0, row = 1, columnspan = 3, padx = 5, pady = 5)

 

main_window.mainloop()

 

Output:

 

반응형
반응형

GUI 생성

지금까지 콘솔 출력에 데이터를 표시하는 Python 코드를 작성했습니다. 그러나 대부분의 최신 Python 응용 프로그램에서는 GUI(그래픽 사용자 인터페이스)를 개발해야 합니다. 다양한 Python 라이브러리를 사용하여 GUI를 개발할 수 있습니다. 그러나 Tkinter GUI 개발을 위한 유일한 내장 Python 라이브러리입니다.

 

Tkinter로 간단한 다이얼로그를 만들려면 아래 스크립트와 같이 Tkinter 모듈의 Tk 클래스를 사용할 수 있습니다.

Tk 클래스의 객체에서 mainloop() 메서드를 호출해야 합니다.

mainloop() 메서드는 화면에 다이얼로그를 계속 표시합니다. mainloop() 메서드가 없으면 다이얼로그가 나타나고 즉시 사라집니다.

 

Output:

 

title 속성을 사용하여 다이얼로그의 제목을 설정할 수 있습니다.

마찬가지로 창의 너비, 높이, 위치를 설정하기 위해 geometry 속성을 사용할 수 있습니다. 너비와 높이(픽셀) 및 화면 상단과 왼쪽으로부터의 거리는 다음 형식으로 지정됩니다.

 

너비 x 높이 + 왼쪽으로부터의 거리 + 상단으로부터의 거리.

 

다음 스크립트는 창의 너비와 높이를 500픽셀로 설정하고 화면 왼쪽으로부터의 거리는 100픽셀이고 화면 상단으로부터의 거리는 200픽셀로 설정한 다이얼로그 예제입니다.

 

Output:

 

다이얼로그에 간단한 레이블을 추가해 보겠습니다. 그렇게 하려면 Label 클래스 객체를 만들어야 합니다. 생성자에서 레이블을 첨부하려는 다이얼로그 이름이 첫 번째 매개변수로 전달됩니다.

또한 레이블을 다이얼로그에 추가하려면 Label 클래스 객체에서 pack() 메서드를 호출해야 합니다.

 

Output:

 

위젯 작업

위젯은 다양한 유형의 작업을 수행하는 데 사용할 수 있는 GUI 객체입니다.

Tkinter에는 테마 위젯과 일반 위젯의 두 가지 유형의 위젯이 있습니다. 테마 위젯은 Tkinter 라이브러리의 tkk 모듈 내부에 있습니다. 일반 위젯은 Tkinter 라이브러리 내부의 최상위 레벨에 있습니다.

 

버튼추가

버튼 위젯을 사용하면 다이얼로그에 클릭 가능한 버튼을 추가할 수 있습니다.

다음 스크립트는 my_button이라는 테마 버튼을 다이얼로그에 추가합니다. 테마 버튼을 생성하려면 tkk.Button 클래스의 객체를 생성해야 합니다.

모든 위젯의 첫 번째 매개변수는 위젯을 연결하려는 다이얼로그입니다. 다른 매개변수들은 각각의 위젯에 따라 다릅니다. 예를 들어, 테마 버튼의 경우 text 속성을 통해 버튼 텍스트를 지정할 수 있습니다.

command 속성을 사용하여 버튼을 클릭할 때 호출되는 콜백 함수를 지정할 수도 있습니다.

마지막으로 기본 다이얼로그에 연결해야 하는 모든 위젯에서 pack() 메서드를 호출해야 합니다.

 

Output:

 

텍스트 필드 추가

다이얼로그에 텍스트 필드를 추가해 보겠습니다. 텍스트 필드를 추가하려면 항목 위젯을 사용할 수 있습니다. 항목 위젯은 테마 위젯뿐만 아니라 단순 위젯으로도 사용할 수 있습니다.

기본 다이얼로그 속성과 별도로 Entry 필드에 입력한 텍스트를 Entry 클래스의 textvariable 속성을 사용하여 StringVar의 객체에 바인딩할 수 있습니다.

다음 스크립트는 my_text라는 StringVar 클래스 객체를 초기화합니다. 다음으로 Entry 클래스 객체인 text_field를 정의하여 텍스트 필드를 생성합니다.

 

Entry 클래스의 속성은 다음과 같습니다.

첫 번째 매개변수 값은 평소와 같이 텍스트 필드가 첨부될 다이얼로그입니다.

두 번째 매개변수는 my_text 객체로, textvariable 속성에 할당됩니다. 텍스트 변수에 입력된 텍스트를 검색하려면 my_text 객체를 통해 get() 메서드를 호출하면 됩니다.

 

마지막으로 text_field 객체를 통해 pack() 메서드를 호출할 수 있습니다. 여기에서 확장 속성의 값으로 True를 전달했음을 주목하세요. 그러면 위젯이 기본 창의 전체 너비로 확장됩니다.

 

Output:

텍스트 필드의 다른 예를 살펴보겠습니다.

다음 스크립트는 기본 다이얼로그에 두 개의 위젯을 추가합니다.

첫 번째는 텍스트 필드이고 두 번째는 버튼입니다.

버튼의 콜백 함수는 my_func()입니다. 버튼을 클릭하면 get() 메서드를 사용하여 텍스트 필드의 텍스트를 검색합니다. 텍스트 필드가 비어 있으면 필드에 일부 텍스트를 입력하라는 메시지가 표시됩니다. 그렇지 않으면 필드의 텍스트가 콘솔에 표시됩니다.

 

Output:

 

반응형
반응형

스레드 간 통신 (Inter-Thread Communication)

프로그램을 실행하는 동안 스레드는 서로 상호 작용해야 하며 이를 스레드 간 통신이라고 합니다. 예를 들어, 생산자-소비자 문제에서 생산자는 품목을 생산한 후 소비자가 소비할 수 있도록 품목이 생산되었음을 소비자에게 알려주어야 합니다.

 

이벤트 객체 사용

스레드 간 통신을 위한 가장 간단한 방법은 이벤트 객체를 사용하는 것입니다. 스레드 중 하나는 신호를 보내고 다른 스레드는 수신을 기다립니다.

 

기본 구문은 다음과 같습니다.

(이벤트 객체 생성) = threading.Event()

 

event_class의 메서드

1. set(): 내부 플래그를 True로 설정하고 대기 중인 모든 스레드가 깨어납니다.

2. clear(): 내부 플래그를 False로 설정하고 대기 중인 모든 스레드는 set()을 호출할 때가지 블록됩니다.

3. isSet(): 지정된 이벤트가 설정되었는지 확인하기 위해 사용합니다.

4. wait() 또는 wait(seconds): 스레드는 이벤트가 설정될 때까지 대기합니다.

 

from threading import *

import time

 

def producer():

    time.sleep(3)

    print("Producer thread producing items:")

    print("Producer thread notification")

    time.sleep(3)

    event.set()

    

def consumer():

    print("Consumer thread waiting")

    event.wait()

    print("Consumer thread consuming items")

    

event = Event()

t1 = Thread(target = producer)

t2 = Thread(target = consumer)

t1.start()

t2.start()

 

Output:

Consumer thread waiting

Producer thread producing items:

Producer thread notification

Consumer thread consuming items

 

Condition 객체 사용

스레드 간 통신을 위한 또 다른 방법은 조건 객체입니다. 조건은 생산자가 품목을 생산하거나 소비자가 품목을 소비하는 등 상태에 변화가 있음을 나타냅니다. 스레드는 해당 조건이 발생할 때까지 기다리며 발생 후 알림을 받습니다. 조건은 잠금과 관련하여 정의됩니다.

 

(조건 객체 생성) = threading.Condition()

 

조건 객체의 메서드

1) acquire(): 조건 객체를 얻는 데 사용됩니다. , 스레드가 내부 잠금을 획득합니다.

2) release(): condition 객체를 해지하기 위해 사용한다. 스레드는 내부 잠금을 해제합니다.

3) wait() 또는 wait(time): 스레드는 알림이나 시간 만료를 받을 때까지 기다립니다.

4) notify(): 대기 중인 스레드 중 하나로 알림이 전송됩니다.

5) notifyAll(): 모든 대기 스레드에 알림이 전송됩니다.

 

다음 스크립트는 Condition 사용법을 보여주고 있습니다. 생산자의 스레드는 리소스에 항목을 생성하고 조건을 획득한 후 소비자에게 신호를 보내기 위해 notify()로 알람을 보냅니다. 반면에 소비자는 조건을 획득한 다음 대기하고 있다가 생산자로부터 알람을 받으면 리소스에서 항목을 소비해야 합니다.

 

from threading import *

import time

 

def producer(c):

    c.acquire()

    print("Producer producing items:")

    print("Producer notification")

    c.notify()

    c.release()

    

def consumer(c):

    c.acquire()

    print("Consumer waiting")

    c.wait()

    print("Consumer notification")

    c.release

    

c = Condition()

t1 = Thread(target = consumer, args = (c,))

t2 = Thread(target = producer, args = (c,))

t1.start()

t2.start()

 

Output:

Consumer waiting

Producer producing items:

Producer notification

Consumer notification

 

Queue 사용

스레드 간 통신을 위한 마지막 방법은 큐를 사용하는 것입니다. 스레드 간 통신에 가장 선호되는 방법입니다. 내부적으로 queue에는 잠금과 관련된 조건이 있습니다. 따라서 queue로 작업하는 동안 동기화에 대해 생각할 필요가 없습니다.

 

사용하는 방법은 다음과 같습니다.

import queue

queue 객체 생성 = queue.Queue()

 

queue 메서드

1)    put() : queue에 항목을 넣습니다.

2)    get() : 항목을 제거하고 quque에서 항목을 반환합니다.

 

다음 스크립트는 queue를 사용한 예제입니다.

생산자 스레드는 put() 메서드를 사용하여 데이터 항목을 queue에 추가합니다.

데이터 항목을 추가하면 잠금이 자동으로 해제됩니다. put() 메소드는 또한 큐가 가득 찼는지 여부를 확인하고 큐가 가득 찼음을 발견하면 생산자 스레드는 wait() 메소드를 호출하여 대기 상태에 들어갈 것입니다. 소비자 스레드는 get() 메서드를 사용하여 큐에서 데이터를 제거하고 가져옵니다. 제거가 완료되면 잠금이 자동으로 해제됩니다. 큐가 비어 있으면 소비자 스레드는 wait() 메서드를 호출하여 대기 상태에 들어갑니다. 큐가 데이터로 업데이트되면 스레드는 자동으로 알림을 받습니다.

 

from threading import *

import time

import random

import queue

 

def producer(q):

    while True:

        item = random.randint(1, 25)

        print("Producer Producting Item: ", item)

        q.put(item)

        print("Producer Notification")

        time.sleep(3)

    

def consumer(q):

    while True:

        print("Consumer waiting ")

        print("Consumer consumed the item:", q.get())

        time.sleep(3)

    

q = queue.Queue()

t1 = Thread(target = consumer, args = (q,))

t2 = Thread(target = producer, args = (q,))

t1.start()

t2.start()

 

Output:

Consumer waiting

Producer Producting Item:  11

Producer Notification

Consumer consumed the item: 11

Consumer waiting

Producer Producting Item:  19

Producer Notification

Consumer consumed the item: 19

Producer Producting Item:  21

Producer Notification

Consumer waiting

Consumer consumed the item: 21

Producer Producting Item:  7Consumer waiting

Producer Notification

…..

 

First-In-First-Out Queue

큐에 처음 삽입된 항목이 대기열에서 가장 먼저 제거됩니다.

 

import queue

 

q = queue.Queue()

q.put(12)

q.put(15)

q.put(22)

while not q.empty():

    print(q.get(), end=' ')

 

Output:

12 15 22

 

Last-In-First-Out Queue

큐에 처음 삽입된 항목이 대기열에서 마지막으로 제거됩니다.

 

import queue

 

q = queue.LifoQueue()

q.put(12)

q.put(15)

q.put(22)

while not q.empty():

    print(q.get(), end=' ')

 

Output:

22 15 12

 

Priority Queue

항목은 할당된 우선 순위에 따라 삽입됩니다.

 

import queue

 

q = queue.PriorityQueue()

q.put(12)

q.put(15)

q.put(22)

while not q.empty():

    print(q.get(), end=' ')

 

Output:

12 15 22

반응형
반응형

스레드 동기화(Thread Synchronization)

여러 스레드가 동시에 실행되면 데이터 불일치 문제가 발생할 수 있습니다. 동기화를 사용하면 이 문제를 방지할 수 있습니다. 동기화는 데이터 불일치 문제를 극복하기 위해 한 번에 하나의 스레드만 실행할 수 있도록 합니다. 동기화는 실행해야 하는 스레드가 둘 이상인 경우 한 번에 단일 스레드가 임계 영역에 액세스할 수 있도록 보장하는 메커니즘입니다.

동기화 프리미티브를 보장하는 동안 교착 상태 및 경쟁 조건과 같은 두 가지 주요 문제가 발생할 수 있습니다.

 

다음 스크립트는 두 스레드가 함께 실행되어 불규칙하게 출력되는 모습을 보여주고 있습니다.

 

from threading import *

import time

 

def func(n):  

  for i in range(2):

    print("Hi:", end='')

    time.sleep(2)

    print(n)

 

t1 = Thread(target = func, args = ("Park", ))

t2 = Thread(target = func, args = ("Kim", ))

t1.start()

t2.start()

 

Output:

Hi:Hi:ParkKim

Hi:

Hi:Kim

Park

 

 

Lock 사용

Lock에는 두 가지 정의된 상태가 있습니다. 하나는 잠금 상태이고 다른 하나는 잠금 해제 상태입니다.

Lock은 초기 생성 시에 잠금 해제 상태로 생성됩니다. 지원되는 두 가지 메서드는 acquire() release()가 있습니다.

Lockacquire()하면 해당 스레드만 공유 데이터에 접근할 수 있고 Lockrelease()해야만 다른 스레드에서 공유 데이터에 접근 할 수 있습니다.

 

acquire()

-  잠금 상태인 경우, 다른 스레드에서 release()호출을 통해서 잠금 해지 상태로 바꿀 때까지 블록 됩니다. 잠금 상태에서 acquire() 메서드를 호출하면 다시 잠금으로 재설정하고 반환합니다.

-  잠금 해지 상태인 경우, 잠금 상태로 변경하고 반환합니다.

release()

-  잠금 상태인 경우, 잠금 해지 상태로 변경합니다.

-  잠금 해지 상태인 경우, RuntimeError가 발생합니다.

 

다음 스크립트는 잠금 해지 상태에서 release()를 호출했을 때 발생하는 오류입니다.

 

from threading import *

 

lock = Lock()

lock.release()

 

Output:

RuntimeError: release unlocked lock

 

다음 스크립트는 acquire()release()를 사용하는 방법을 보여주고 있습니다. 두 스레드가 순차적으로 출력하고 있는 모습을 보여주고 있습니다.

 

from threading import *

import time

 

lock = Lock()

 

def func(n): 

  lock.acquire() 

  for i in range(2):

    print("Hi:", end='')

    print(n)

  lock.release()

 

t1 = Thread(target = func, args = ("Park", ))

t2 = Thread(target = func, args = ("Kim", ))

t1.start()

t2.start()

 

Output:

Hi:Park

Hi:Park

Hi:Kim

Hi:Kim

 

RLock 사용

스레드가 재귀적으로 리소스에 액세스하면 스레드가 동일한 잠금을 다시 획득하여 스레드가 차단될 수 있습니다. 따라서 Lock 잠금 방법은 재귀 함수 실행에 적합하지 않습니다. 이러한 문제를 처리하기 위해 재진입 잠금(RLock)이 선호됩니다.

재진입 잠금은 동일한 스레드가 여러 번 획득할 수 있는 동기화 프리미티브입니다.

기본 잠금에서 사용되는 잠금 또는 잠금 해제 상태 외에 스레드 및 재귀 수준을 소유한다는 개념을 따릅니다.

잠금 상태의 경우 일부 스레드가 잠금을 소유하는 반면 잠금 해제 상태의 경우 잠금을 소유하는 스레드가 없습니다.

스레드는 잠금을 수행하기 위해 acquire() 메서드를 호출하고 반환합니다.

스레드는 잠금을 해제하기 위해 release() 메서드를 호출합니다.

 

from threading import *

 

lock = RLock()

 

def fact(n):

    lock.acquire() 

    if n == 0:

        opt = 1

    else:

        opt = n * fact(n-1)

    lock.release()

    return opt

 

def opt(n):

    print("Factorial", n, ":", fact(n))

 

t1 = Thread(target = opt, args = (3, ))

t2 = Thread(target = opt, args = (5, ))

t1.start()

t2.start()

 

Output:

Factorial 3 : 6

Factorial 5 : 120

 

다음 표는 LockRlock의 차이를 보여줍니다.

 

Lock Rlock
- 메인 스레드를 포함하여 한 번에 하나의 스레드만 획득할 수 있습니다.
 
- 재귀 및 중첩 함수에서는 선호되지 않습니다.
 
- 객체의 잠금 및 잠금 해제만 담당합니다. 메인 쓰레드와 재귀 수준을 고려하지 않습니다.
- 한 번에 하나의 스레드만 획득할 수 있지만 메인 스레드는 여러 번 획득할 수 있습니다.
 
- 재귀 및 중첩 함수에 가장 적합합니다.
 
 
- 잠금, 잠금 해제, 메인 스레드 및 재귀 수준도 담당합니다.
 

 

세마포어 사용

세마포어는 공유 리소스의 액세스를 제한하는 데 선호됩니다.

세마포어는 모든 acquire() 호출에 의해 감소되고 모든 release() 호출에 의해 증가되는 내부 카운터를 처리합니다. 카운터는 0보다 작을 수 없습니다. 카운터는 동시에 액세스할 수 있는 최대 스레드 수를 나타냅니다. 기본값은 1입니다.

 

기본 구문은 다음과 같습니다.

(세마포어 객체 생성) = Semaphore(counter)

 

사용 예)

s = Semaphore()

여기에서 카운터 값은 1이고 한 번에 하나의 스레드에만 액세스가 허용됩니다.

s = Semaphore(3)

여기서 세마포어 객체는 세 개의 스레드에서 동시에 액세스할 수 있습니다. 나머지 스레드는 세마포어가 해제될 때까지 기다려야 합니다.

 

다음 스크립트는 세마포어의 카운터를 1로 설정하고 수행한 예제입니다. 카운터가 1이므로 한번에 하나의 스레드에만 액세스 할 수 있어서 순차적으로 출력됨을 보여주고 있습니다.

 

from threading import *

import time

 

s = Semaphore(1)

 

def func(n): 

    s.acquire() 

    for i in range(2):

        print("Hi:", end='')

        time.sleep(2)

        print(n)

    s.release()

 

t1 = Thread(target = func, args = ("Park", ))

t2 = Thread(target = func, args = ("Kim", ))

t1.start()

t2.start()

 

Output:

Hi:Park

Hi:Park

Hi:Kim

Hi:Kim

 

다음 스크립트는 세마포어의 카운터를 2로 설정하고 수행한 예제입니다. 두개의 스레드에 동시에 접근하므로 불규칙하게 출력됩니다.

 

from threading import *

import time

 

s = Semaphore(2)

 

def func(n): 

    s.acquire() 

    for i in range(2):

        print("Hi:", end='')

        time.sleep(2)

        print(n)

    s.release()

 

t1 = Thread(target = func, args = ("Park", ))

t2 = Thread(target = func, args = ("Kim", ))

t1.start()

t2.start()

 

Output:

Hi:Hi:KimPark

Hi:

Hi:Park

Kim

반응형

+ Recent posts