目次
无效唤醒" >无效唤醒
A进程:" >A进程:
B进程:" >B进程:
避免无效唤醒" >避免无效唤醒
Linux内核的例子" >Linux内核的例子
TASK_INTERRUPTIBLE または " >上記の説明を通じて、Linux でプロセスの無効なウェイクアップを回避する鍵は、プロセスのステータスを TASK_INTERRUPTIBLE または
ホームページ システムチュートリアル Linux Linux プロセスのウェイクとスリープ

Linux プロセスのウェイクとスリープ

Feb 10, 2024 pm 04:40 PM
linux Linuxチュートリアル Linuxシステム Linux オペレーティング システム Linuxコマンド シェルスクリプト 埋め込みLinux Linux を始める Linux学習

Linux システムでは、CPU 時間を待機しているプロセスのみが準備完了プロセスと呼ばれます。これらは、ステータス フラグ TASK_RUNNING とともに実行キューに配置されます。実行中のプロセスがタイム スライスを使い果たすと、Linux カーネル スケジューラは CPU の制御を奪い、実行キューから適切なプロセスを選択して実行します。

Linux 进程的唤醒和睡眠

もちろん、プロセスは CPU の制御を積極的に放棄することもできます。 schedule() この関数は、プロセスによってアクティブに呼び出されて、他のプロセスが CPU を占有するようにスケジュールできるスケジューリング関数です。 CPU を積極的に放棄するプロセスが CPU を占有するように再スケジュールされると、最後に停止した位置、つまり schedule() を呼び出すコードの次の行から実行を開始します。

プロセスは、デバイスの初期化の完了、I/O 操作の完了、タイマーの期限切れなど、特定のイベントが発生するまで待機する必要がある場合があります。この場合、プロセスは実行キューから削除され、待機キューに追加される必要があり、その時点でプロセスはスリープ状態になります。

Linux には 2 つのプロセス スリープ状態があります:

  • 1 つは、ステータス フラグ TASK_INTERRUPTIBLE を持つ、割り込み可能なスリープ状態です。
  • もう 1 つは中断不可能なスリープ状態であり、そのステータス フラグは TASK_UNINTERRUPTIBLE です。

割り込み可能なスリープ状態にあるプロセスは、特定の条件が true になるまでスリープします。たとえば、ハードウェア割り込みの生成、プロセスが待機しているシステム リソースの解放、またはシグナルの通過がスリープ状態を解除する条件になる可能性があります。プロセスを上げます。中断不可能なスリープ状態は中断可能なスリープ状態と似ていますが、例外が 1 つあります。つまり、このスリープ状態に信号を送信するプロセスはその状態を変更できません。つまり、ウェイクアップする信号に応答しません。通常、中断不可能なスリープ状態はあまり使用されませんが、特定のイベントが発生するまでプロセスを待機する必要があり、中断できないなど、特定の状況では依然として非常に役立ちます。

最近の Linux オペレーティング システムでは、通常、schedule() を呼び出すことでプロセスがスリープ状態に入ります。次のコードは、実行中のプロセスをスリープ状態にする方法を示しています。

リーリー

最初のステートメントでは、プログラムはプロセス構造ポインター sleeping_task を格納します。current はマクロであり、実行中のプロセス構造を指します。

set_current_state() プロセスの状態を実行状態 TASK_RUNNING からスリープ状態 TASK_INTERRUPTIBLE に変更します。 schedule() がステータス TASK_RUNNING のプロセスによってスケジュールされている場合、schedule() は別のプロセスが CPU を占有するようにスケジュールします。

如果 schedule() 是被一个状态为 TASK_INTERRUPTIBLETASK_UNINTERRUPTIBLE 的进程调度,那么还有一个附加的步骤将被执行:当前执行的进程在另外一个进程被调度之前会被从运行队列中移出,这将导致正在运行的那个进程进入睡眠,因为它已经不在运行队列中了。

我们可以使用下面的这个函数将刚才那个进入睡眠的进程唤醒。

wake_up_process(sleeping_task);
ログイン後にコピー

在调用了 wake_up_process() 以后,这个睡眠进程的状态会被设置为 TASK_RUNNING,而且调度器会把它加入到运行队列中去。当然,这个进程只有在下次被调度器调度到的时候才能真正地投入运行。

无效唤醒

几乎在所有的情况下,进程都会在检查了某些条件之后,发现条件不满足才进入睡眠。可是有的时候进程却会在判定条件为真后开始睡眠,如果这样的话进程就会无限期地休眠下去,这就是所谓的无效唤醒问题。

在操作系统中,当多个进程都企图对共享数据进行某种处理,而 最后的结果又取决于进程运行的顺序时,就会发生竞争条件,这是操作系统中一个典型的问题,无效唤醒恰恰就是由于竞争条件导致的。

设想有两个进程A 和B,A 进程正在处理一个链表,它需要检查这个链表是否为空,如果不空就对链表里面的数据进行一些操作,同时B进程也在往这个链表添加节点。当这个链表是空的时候,由于无数据可操作,这时A进程就进入睡眠,当B进程向链表里面添加了节点之后它就唤醒A 进程,其代码如下:

A进程:
1 spin_lock(&list_lock);
2 if (list_empty(&list_head)) {
3     spin_unlock(&list_lock);
4     set_current_state(TASK_INTERRUPTIBLE);
5     schedule();
6     spin_lock(&list_lock);
7 }
8
9 /* Rest of the code ... */
10 spin_unlock(&list_lock);
ログイン後にコピー
B进程:
100 spin_lock(&list_lock);
101 list_add_tail(&list_head, new_node);
102 spin_unlock(&list_lock);
103 wake_up_process(processa_task);
ログイン後にコピー

这里会出现一个问题,假如当A进程执行到第3行后第4行前的时候,B进程被另外一个处理器调度投入运行。在这个时间片内,B进程执行完了它所有的指令,因此它试图唤醒A进程,而此时的A进程还没有进入睡眠,所以唤醒操作无效。

在这之后,A 进程继续执行,它会错误地认为这个时候链表仍然是空的,于是将自己的状态设置为 TASK_INTERRUPTIBLE 然后调用 schedule() 进入睡 眠。由于错过了B进程唤醒,它将会无限期的睡眠下去,这就是无效唤醒问题,因为即使链表中有数据需要处理,A 进程也还是睡眠了。

避免无效唤醒

如何避免无效唤醒问题呢?

我们发现无效唤醒主要发生在检查条件之后和进程状态被设置为睡眠状态之前,本来B进程的 wake_up_process() 提供了一次将A进程状态置为 TASK_RUNNING 的机会,可惜这个时候A进程的状态仍然是 TASK_RUNNING,所以 wake_up_process() 将A进程状态从睡眠状态转变为运行状态的努力 没有起到预期的作用。

要解决这个问题,必须使用一种保障机制使得判断链表为空和设置进程状态为睡眠状态成为一个不可分割的步骤才行,也就是必须消除竞争条 件产生的根源,这样在这之后出现的 wake_up_process() 就可以起到唤醒状态是睡眠状态的进程的作用了。

找到了原因后,重新设计一下A进程的代码结构,就可以避免上面例子中的无效唤醒问题了。

A进程:
1 set_current_state(TASK_INTERRUPTIBLE);
2 spin_lock(&list_lock);
3 if (list_empty(&list_head)) {
4     spin_unlock(&list_lock);
5     schedule();
6     spin_lock(&list_lock);
7 }
8 set_current_state(TASK_RUNNING);
9
10 /* Rest of the code ... */
11 spin_unlock(&list_lock);
ログイン後にコピー

可以看到,这段代码在测试条件之前就将当前执行进程状态转设置成 TASK_INTERRUPTIBLE 了,并且在链表不为空的情况下又将自己置为 TASK_RUNNING 状态。

这样一来如果B进程在A进程进程检查了链表为空以后调用 wake_up_process(),那么A进程的状态就会自动由原来 TASK_INTERRUPTIBLE 变成 TASK_RUNNING,此后即使进程又调用了 schedule(),由于它现在的状态是 TASK_RUNNING,所以仍然不会被从运行队列中移出,因而不会错误的进入睡眠,当然也就避免了无效唤醒问题。

Linux内核的例子

在Linux操作系统中,内核的稳定性至关重要,为了避免在Linux操作系统内核中出现无效唤醒问题,Linux内核在需要进程睡眠的时候应该使用类似如下的操作:

/* q 是我们希望睡眠的等待队列 */
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
/* condition 是等待的条件 */
while (!condition) {
    schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(q, &wait);
ログイン後にコピー

上面的操作,使得进程通过下面的一系列步骤安全地将自己加入到一个等待队列中进行睡眠:首先调用 DECLARE_WAITQUEUE() 创建一个等待队列的项,然后调用 add_wait_queue() 把自己加入到等待队列中,并且将进程的状态设置为 TASK_INTERRUPTIBLE 或者 TASK_INTERRUPTIBLE

然后循环检查条件是否为真:如果是的话就没有必要睡眠,如果条件不为真,就调用 schedule()。当进程检查的条件满足后,进程又将自己设置为 TASK_RUNNING 并调用 remove_wait_queue() 将自己移出等待队列。

从上面可以看到,Linux的内核代码维护者也是在进程检查条件之前就设置进程的状态为睡眠状态,然后才循环检查条件。如果在进程开始睡眠之前条件就已经达成了,那么循环会退出并用 set_current_state() 将自己的状态设置为就绪,这样同样保证了进程不会存在错误的进入睡眠的倾向,当然也就不会导致出现无效唤醒问题。

下面让我们用 Linux 内核中的实例来看看其是如何避免无效睡眠的,这段代码出自 Linux2.6 的内核 (/kernel/sched.c):

/* Wait for kthread_stop */
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
    schedule();
    set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
return 0;
ログイン後にコピー

上面的这些代码属于迁移服务线程 migration_thread,这个线程不断地检查 kthread_should_stop(),直到 kthread_should_stop() 返回 1 它才可以退出循环,也就是说只要 kthread_should_stop() 返回 0 该进程就会一直睡眠。

从代码中我们可以看出,检查 kthread_should_stop() 确实是在进程的状态被置为 TASK_INTERRUPTIBLE 后才开始执行的。因此,如果在条件检查之后但是在 schedule() 之前有其他进程试图唤醒它,那么该进程的唤醒操作不会失效。

######まとめ######

上記の説明を通じて、Linux でプロセスの無効なウェイクアップを回避する鍵は、プロセスのステータスを TASK_INTERRUPTIBLE または

TASK_UNINTERRUPTIBLE

に設定することであることがわかります。プロセスが条件をチェックする前に、チェックされた条件が満たされた場合、ステータスは TASK_RUNNING にリセットされます。 これにより、プロセスの待機条件が成立するか否かに関わらず、プロセスがレディキューから外されるため、誤ってスリープ状態に移行することがなくなり、無効ウェイクアップの問題が回避されます。

以上がLinux プロセスのウェイクとスリープの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Deepseek Webバージョンの入り口Deepseek公式ウェブサイトの入り口 Deepseek Webバージョンの入り口Deepseek公式ウェブサイトの入り口 Feb 19, 2025 pm 04:54 PM

DeepSeekは、Webバージョンと公式Webサイトの2つのアクセス方法を提供する強力なインテリジェント検索および分析ツールです。 Webバージョンは便利で効率的であり、公式ウェブサイトは包括的な製品情報、ダウンロードリソース、サポートサービスを提供できます。個人であろうと企業ユーザーであろうと、DeepSeekを通じて大規模なデータを簡単に取得および分析して、仕事の効率を向上させ、意思決定を支援し、イノベーションを促進することができます。

DeepSeekをインストールする方法 DeepSeekをインストールする方法 Feb 19, 2025 pm 05:48 PM

DeepSeekをインストールするには、Dockerコンテナ(最も便利な場合は、互換性について心配する必要はありません)を使用して、事前コンパイルパッケージ(Windowsユーザー向け)を使用してソースからコンパイル(経験豊富な開発者向け)を含む多くの方法があります。公式文書は慎重に文書化され、不必要なトラブルを避けるために完全に準備します。

LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? Apr 01, 2025 pm 05:09 PM

LinuxターミナルでPythonバージョンを表示する際の許可の問題の解決策PythonターミナルでPythonバージョンを表示しようとするとき、Pythonを入力してください...

Bitget公式ウェブサイトのインストール(2025初心者ガイド) Bitget公式ウェブサイトのインストール(2025初心者ガイド) Feb 21, 2025 pm 08:42 PM

Bitgetは、スポット取引、契約取引、デリバティブなど、さまざまな取引サービスを提供する暗号通貨交換です。 2018年に設立されたこのExchangeは、シンガポールに本社を置き、安全で信頼性の高い取引プラットフォームをユーザーに提供することに取り組んでいます。 Bitgetは、BTC/USDT、ETH/USDT、XRP/USDTなど、さまざまな取引ペアを提供しています。さらに、この取引所はセキュリティと流動性について評判があり、プレミアム注文タイプ、レバレッジド取引、24時間年中無休のカスタマーサポートなど、さまざまな機能を提供します。

gate.ioインストールパッケージを無料で入手してください gate.ioインストールパッケージを無料で入手してください Feb 21, 2025 pm 08:21 PM

Gate.ioは、インストールパッケージをダウンロードしてデバイスにインストールすることで使用できる人気のある暗号通貨交換です。インストールパッケージを取得する手順は次のとおりです。Gate.ioの公式Webサイトにアクセスし、「ダウンロード」をクリックし、対応するオペレーティングシステム(Windows、Mac、またはLinux)を選択し、インストールパッケージをコンピューターにダウンロードします。スムーズなインストールを確保するために、インストール中に一時的にウイルス対策ソフトウェアまたはファイアウォールを一時的に無効にすることをお勧めします。完了後、ユーザーはGATE.IOアカウントを作成して使用を開始する必要があります。

OUYI OKXインストールパッケージが直接含まれています OUYI OKXインストールパッケージが直接含まれています Feb 21, 2025 pm 08:00 PM

世界をリードするデジタル資産交換であるOuyi Okxは、安全で便利な取引体験を提供するために、公式のインストールパッケージを開始しました。 OUYIのOKXインストールパッケージは、ブラウザに直接インストールでき、ユーザー向けの安定した効率的な取引プラットフォームを作成できます。インストールプロセスは、簡単で理解しやすいです。

システムの再起動後にUnixSocketの権限を自動的に設定する方法は? システムの再起動後にUnixSocketの権限を自動的に設定する方法は? Mar 31, 2025 pm 11:54 PM

システムが再起動した後、UnixSocketの権限を自動的に設定する方法。システムが再起動するたびに、UnixSocketの許可を変更するために次のコマンドを実行する必要があります:sudo ...

OUYI Exchangeダウンロード公式ポータル OUYI Exchangeダウンロード公式ポータル Feb 21, 2025 pm 07:51 PM

OKXとしても知られるOUYIは、世界をリードする暗号通貨取引プラットフォームです。この記事では、OUYIの公式インストールパッケージのダウンロードポータルを提供します。これにより、ユーザーはさまざまなデバイスにOUYIクライアントをインストールすることが容易になります。このインストールパッケージは、Windows、Mac、Android、およびiOSシステムをサポートします。インストールが完了した後、ユーザーはOUYIアカウントに登録またはログインし、暗号通貨の取引を開始し、プラットフォームが提供するその他のサービスを楽しむことができます。

See all articles