6

CPUを集中的に使用するタスクをバックグラウンドで実行しているときに、Linuxデスクトップエクスペリエンスをスムーズかつインタラクティブに保つ方法を調査しています。これは、CPU負荷をシミュレートするために使用しているサンプルプログラム(Javaで記述)です。

public class Spinner {
    public static void main(String[] args)
    {
        for (int i = 0; i < 100; i++) {
            (new Thread(new Runnable() {
                    public void run() {
                        while (true);
                    }
            })).start();
        }
    }
}

これをコマンドラインで実行すると、デスクトップアプリケーション(テキストエディタなど)の対話性が大幅に低下することに気付きます。私はデュアルコアマシンを持っているので、これには驚いていません。

これに対抗するために、私の最初の考えは、でプロセスを改善renice -p 20 <pid>することでした。しかし、これはあまり影響がないことがわかりました。代わりに、すべての子プロセスをls /proc/<pid>/task | xargs renice 20 -p --、はるかに大きな効果を持つようなもので放棄する必要があります。

スレッドが独自のプロセスIDを持っているとは思わないので、私はこれに非常に混乱しています。renice彼らがそうしたとしても、私はプロセスのメインスレッドだけでなく、プロセス全体に作用することを期待していました。

ここで何が起こっているのかを明確に理解している人はいますか? 各スレッドは実際には別個のプロセスであるように見えます(少なくとも有効なPIDがあります)。歴史的にLinuxがこのように機能することは知っていましたが、NPTLはその数年前に修正されたと思いました。

RHEL 5.4(Linuxカーネル2.6.18)でテストしています。

(余談ですが、sched_setscheduler(<pid>, SCHED_BATCH, ..)この対話性の問題を解決するために使用しようとすると、同じ効果に気付きます。つまり、表示されるすべての「子」プロセスに対してこの呼び出しを行う必要があります。/proc/<pid>/task一度実行するだけでは不十分です。メインプログラムpidで。)

4

2 に答える 2

2

スレッドIDは、PIDと同じ名前空間から取得されます。これは、各スレッドがそのTIDによって個別にアドレス可能であることを意味します。一部のシステムコールはプロセス全体に適用されますが(たとえばkill)、他のスレッドは単一のスレッドにのみ適用されます。

スケジューラシステムコールは通常、後者のクラスにあります。これにより、プロセス内のさまざまなスレッドにさまざまなスケジューラ属性を与えることができるため、多くの場合便利です。

于 2011-07-28T05:08:41.940 に答える
2

私が理解しているように、Linuxではスレッドとプロセスはほとんど同じです。スレッドはたまたま、forkのコピーオンライトを実行するのではなく、同じメモリを共有するプロセスであり、fork(2)pthread_create(3)は、おそらく両方とも、異なる引数を使用 してclone(2)の呼び出しに階層化されています。

たとえば、pthreads(7)のマニュアルページは、Posixスレッドが共通の優れた値を共有していることを示すことから始まりますが、その後、

NPTLにはまだPOSIX.1とのいくつかの不適合があります:スレッドは共通の素晴らしい値を共有していません

全体像を見ることができます(そして、あまり役に立たないマニュアルページがたくさんあると確信しています)。

メインUIスレッドから複数の計算スレッドを生成するGUIアプリを作成しましたが、アプリの応答性を維持するための鍵は、計算スレッドでnice(2)を呼び出すことです(のみ)。4程度増やすとうまくいくようです。

または、少なくともそれは私がやったことを覚えていたものです。私は数年ぶりにコードを見て、実際に何をしたかを確認しました。

// Note that this code relies on Linux NPTL's non-Posix-compliant
// thread-specific nice value (although without a suitable replacement
// per-thread priority mechanism it's just as well it's that way).
// TODO: Should check some error codes,
// but it's probably pretty harmless if it fails.

  const int current_priority=getpriority(PRIO_PROCESS,0);
  setpriority(PRIO_PROCESS,0,std::min(19u,current_priority+n)); 

これは興味深いです。私はおそらくnice(2)を試しましたが、実際にはプロセス全体(すべてのスレッド)に適用されることがわかりました。これは私が望んでいたことではありませんでした(ただし、おそらくあなたはそうします)。しかし、これは数年前にさかのぼります。それ以降、動作が変更された可能性があります。

この種のもので遊んでいるときの1つの重要なツール:top(1)で「H」(「h」ではなくNB)を押すと、プロセスビューからすべてのスレッドと個々のスレッドの適切な値が表示されます。たとえば[evolvotron][7] -t 4 -n 5、(nice 5で4つの計算スレッド)を実行すると、次のようになります(古いシングルコアの非HTマシンを使用しているため、ここでは複数のスレッドをあまり使用していません)。

Tasks: 249 total,   5 running, 244 sleeping,   0 stopped,   0 zombie
Cpu(s): 17.5%us,  6.3%sy, 76.2%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1025264k total,   984316k used,    40948k free,    96136k buffers
Swap:  1646620k total,        0k used,  1646620k free,   388596k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND           
 4911 local     25   5 81096  23m  15m R 19.7  2.4   0:04.03 evolvotron         
 4912 local     25   5 81096  23m  15m R 19.7  2.4   0:04.20 evolvotron         
 4913 local     25   5 81096  23m  15m R 19.7  2.4   0:04.08 evolvotron         
 4914 local     25   5 81096  23m  15m R 19.7  2.4   0:04.19 evolvotron         
 4910 local     20   0 81096  23m  15m S  9.8  2.4   0:05.83 evolvotron         
 ...
于 2011-07-28T21:56:31.330 に答える