web-dev-qa-db-ja.com

マルチスレッドはシングルプロセッサシステムに実装できますか?

マルチスレッドは、複数のプロセッサを各スレッドに割り当てる必要があり、各スレッドを同時に実行できるマルチプロセッサシステムでのみ実装できるという概念を常に守ってきました。この場合、スレッドにはそれぞれ専用の個別のリソースがあるため、スケジューリングはありません。しかし、私はどこかで何度も読んで、シングルプロセッサシステムでもマルチスレッドを実行できることを知りました。それが正しいか?はいの場合、シングルプロセッサシステムとマルチプロセッサシステムの違いは何ですか?

57
Ayse

もちろん、シングルプロセッサシステムで実行できます。実際、その方法ははるかに簡単です。複数のプロセスを実行するのと同じように動作します-カーネルは、タイマー割り込みまたは他の同様のメカニズムを介して、1つを中断し、マシン状態を保存し、それを以前に保存した別の状態に置き換えます-唯一の違いは同じプロセスのスレッドは同じ仮想メモリ空​​間を共有するため、タスクスイッチの効率が大幅に向上します。

マルチプロセッサシステムでのマルチスレッドは、実際にははるかに困難です。複数のcpus /コアからメモリへの同時アクセスの問題と、そこから生じる厄介なメモリ同期の問題がすべてあるためです。

51
R..

私はどこかで何度も読んで、シングルプロセッサシステムでもマルチスレッドを実行できることを知りました。それが正しいか?はいの場合、シングルプロセッサシステムとマルチプロセッサシステムの違いは何ですか?

はい、シングルプロセッサシステムでマルチスレッドを実行できます。

マルチプロセッサシステムでは、複数のスレッドが異なるコアで同時にを実行します。たとえば、2つのスレッドと2つのコアがある場合、各スレッドは個別のコアで実行されます。

シングルプロセッサシステムでは、複数のスレッドが次々に実行されるか、スレッドの優先度とOSポリシーに応じて、1つのスレッドが終了するか、OSによってプリエンプトされるまで待機します。 、ユーザー空間アプリケーションの必要なアプリケーション応答時間に関連して。

時間比較(例):

2つのスレッドが実行にそれぞれ10usを要する場合、2プロセッサシステムでは、正味所要時間は10usです

2つのスレッドの実行にそれぞれ10usかかる場合、1プロセッサシステムでは、ネットタイムは20usです

54

クアッドコアシステムでは、4つを超えるアクティブスレッドを使用できます。プロセスがプロセッサより多くのスレッドを作成しようとしないことを保証できない限り、isスケジューリングがあります。

はい、シングルコアコンピューターで複数のスレッドを使用できます。

シングルプロセッサシステムとマルチプロセッサシステムの違いは、マルチプロセッサシステムが実際に一度に複数のことを実行できることです。一度にN個の処理を実行できます。Nはプロセッサコアの数です。シングルプロセッサコアは、一度に1つのことしかできません。 WhozCraigが彼のコメントで述べたように、それは実際の並行性と知覚された並行性の違いです。

7
Jim Mischel

これは非常に単純化された例です。実際には、私が構築しているプログラムのプロトタイプです。これは、単一のスレッドでの協調マルチタスクの実装です。

mainは、単にquitフラグをfalseに設定し、関数ポインター(タスク)の配列を設定して、loopを呼び出します。

loopsetjmpを使用して非ローカルジャンプ(関数のジャンプoutを実行の前の場所に戻すジャンプ)のリターンポイントを設定し、呼び出しに進みます。最初のタスク(関数)。

各タスクはyield()で終了します。つまり、タスク関数はどれもreturnではありません。 return;ステートメントが含まれていないだけでなく(void関数、つまりプロシージャであるため問題ありません)、returnに到達していません。 yieldsetjmp呼び出しにジャンプして戻るため、今回はifloopステートメントに1が返されます。 ifステートメントによって制御されるステートメントは、whileループに再入する前に別のタスクを選択します。

したがって、各タスク関数は複数回実行され、実行する新しいタスクを選択するdispatcherif(setjmp...ステートメント)になります。

#include <stdio.h> 
#include <setjmp.h> 

jmp_buf dispatch; 
int ntasks; 
void (*task[10])(void); 
int quit; 

void yield(void) { 
    longjmp(dispatch, 1); 
} 

void loop() { 
    static int i = 0; 
    if(setjmp(dispatch)) 
        i = (i+1) % ntasks; 
    while(!quit) 
        task[i](); 
} 

int acc = 0; 

void a(void) { 
    if (acc > 10) quit = 1; 
    printf("A\n"); 
    yield(); 
} 
void b(void) { 
    acc *= 2; 
    printf("B\n"); 
    yield(); 
} 
void c(void) { 
    acc += 1; 
    printf("C\n"); 
    yield(); 
} 

int main() { 
    quit = 0; 
    ntasks = 3; 
    task[0] = a; 
    task[1] = b; 
    task[2] = c; 
    loop(); 
    return 0; 
} 

この例とシングルプロセッサマルチタスクコンピュータシステムの違いは、実際のプロセッサが実行中にタスクを中断し、後で同じ場所から再開することをサポートしていることです。これは、タスクが単一の関数であるCシミュレーションでは実際には不可能です。ただし、タスクは、それぞれがディスパッチャに渡す一連のC関数(関数ポインタの配列、またはリンクリスト)で構成できます。

5
luser droog

はい、できます。何年も前(Win 95?)に、協力的なマルチタスクからマルチスレッドに移行しました。誰かが常に協力的な部分を台無しにしてしまったからです。コンピューター上のすべてのプログラムには、少なくとも1つのスレッドがあります。おそらくもっと。 CPUは毎秒数百万回、madのようなすべてのスレッドを切り替え続けます。それらのどれにも関係がない場合は、しばらくアイドル状態になることさえあります。

マルチコアシステムは、これらのスレッドの2つ以上が並列で実行されることを意味するだけです。

しかし、そうすることで得られるものははるかに少なくなります。シングルコアマシンでマルチスレッドを使用してできることは、マルチタスクをシミュレートすることだけです。

Mulitaskingは、長時間実行される操作のためにGUIスレッドがロックするのを防ぐのに十分です。ただし、コンパイラまたはLangauge(C#async ... awaitなど)からの支援がない限り、一般に実装は複雑です。その結果、多くのGUIプログラマーは、マルチスレッドと呼び出しを使用してマルチタスクを偽造しました。そのコードが単一または複数のコアで実行される場合、これには関係ありません。

最も重要なことは、マルチタスクはCPUバウンド操作には適していません。ただし、すべての非同期の問題の95%はCPUバウンドではありません。ネットワークまたはディスクバウンドです。シングルコアコンピューターでは、マルチスレッドはCPUバウンドの問題にも役立ちません。両方とも100%のCPU時間(同じプログラムまたは別のプログラム)を必要とする2つのスレッドがあり、それらを実行するコアが1つだけの場合、CPUは両方を49%で実行し、残りの2%をそれらすべてに使用する必要がありますほんの少しだけ行う他のスレッド。

最後に、実際にマルチスレッド化できる問題はごくわずかです。フィボナッチシーケンス(ペアごとに1つのスレッド)をマルチスレッド化してみてください。低速化、メモリ消費量の増加、複雑化は避けてください。

tl; dr; CPUバウンドの問題には、マルチスレッドとマルチコアコンピューターが必要です。ほとんどの非同期の問題はCPUに依存していません。マルチタスクで十分です。また、シングルコアマシン上でも、スレッドを使用して完全にマルチタスクを実行できます。

3
Christopher