スレッド

スレッドとは

ここではUNIXをベースとしたオペレーティング・システム上でのスレッドベースの並列処理のプログラミングを前提として考えます。

プロセスのフォークによる子プロセスの生成は、親プロセスのもつ計算リソースすべてをコピーして子プロセスを生成します。一方、スレッドは計算リソースはそのままに、CPU資源のみ生成します。そのためにスレッドを生成させるのはプロセスよりも高速になります。一方で、生成されたスレッドが終了しても母体となっているプロセス(この場合は、正確にはタスクと呼ばなければいけませんが、便宜的にここではプロセスと呼びます)は終了しません。

スレッドを使う時、UNIXの古典的プロセスの考え方ではなく「タスク(とスレッド)」という概念を導入しなければいけませんが、ここでは説明し切れませんので別のコンテンツである「プロセス・タスク・スレッド」を参照してください。

さて、並列処理をする際にスレッドを選択する理由は、生成がプロセスよりも軽いという理由の他に、CPUリソース以外の、例えば記憶リソースなどが独立していない(同じものを使っている)点もあげることができます。子プロセスを生成した場合、独立したプロセスになるので、データを共有するのにはひと手間かかります。一方でスレッドの場合、利用している資源は同じなので共有することはできますが、それと同時に同じ資源を取り合う「競合」の問題が発生しやすくなります。

スレッドの生成

サンプルコードではスレッドを生成し、スレッドの中で自分のプロセスIDを表示しています。並列処理をしていますが、どれもすべて同じプロセスIDになっているのがわかると思います。プロセスで説明したサンプルコードと比較するとよく違いがわかると思います。

threadsample.py サンプルコードはLinux version 5.13.0で動作を確認しています。

#
# File: threadsample.py
#
import sys
import os
import time
import threading

def threading_module(msg):
    time.sleep(2)
    print("Thread Start: ",msg,"pid(",os.getpid(),")")
    for t in range(5):
        time.sleep(1)           # 1秒の待ち
        print(msg+':'+str(t))   # 何のプロセスが何回目かを出力

    print("Thread Finish: ",msg,"pid(",os.getpid(),")")

    

if __name__ == "__main__":
    thread_queue=[]             # スレッドを保持しておくため
    for msg in [ 'A','B','C','D','E']:
        th = threading.Thread(target=threading_module, args=(msg,))
        th.start()
        thread_queue.append(th)

    print("***Waiting Join Thread***")
    
    for th in thread_queue:     # スレッド終了時の後処理
        th.join()               # スレッド終了までブロッキングされる
        print(th)

トップページ