MinGWとVS Codeでstd::threadが使えない原因と解決策 this_thread sleep_for対応ガイド

VS Code(または Code::Blocks)+MinGW の構成で C++ の <thread> を使おうとすると、std::thread や std::this_thread::sleep_for が「定義されていない」と出てコンパイルできないことがあります。原因は多くの場合、C++11 以降が有効になっていないか、MinGW 自体が古いこと。この記事では、最短で切り分けて確実に直すための手順を具体例つきで整理します。

目次

起きている症状を整理する

今回のトラブルは、だいたい次のような状態として現れます。

  • std::thread が未宣言・未定義扱いになる
  • std::this_thread が未宣言・未定義扱いになる(例:this_thread was never defined など)
  • オンラインコンパイラ(online-cpp.com 等)では同じコードが動く
  • pthread を入れたつもりでも改善しない

重要なのは、「コンパイル段階のエラー」なのか「リンク段階のエラー」なのかです。
std::thread が定義されていない 系はたいてい コンパイル段階の問題で、まず疑うべきは C++ の規格設定と MinGW の世代です。

先に結論:原因はほぼこの二択

この問題の原因は、現場ではほぼ次の二択に収束します。

原因起きやすい症状最優先の対処
C++11以降が有効になっていない<thread> を include しても std::thread / std::this_thread が見つからない-std=c++20(最低でも -std=c++11)を確実に付ける
MinGW(GCC/標準ライブラリ)が古い規格オプションを付けても改善しない/環境によってはヘッダが不完全MinGW-w64 系など、スレッド対応が整った配布物へ更新する

「pthread を入れたのに…」という相談は多いのですが、今回の主症状が “未定義(コンパイルエラー)” の場合、pthread を足す前に 規格オプションと MinGW 更新が本命です。
pthread 系のオプションは、状況によっては必要ですが、優先順位は後になります(後述します)。

なぜオンラインコンパイラだと動くのか

オンラインコンパイラは、最初から C++17 や C++20 がデフォルトになっていたり、比較的新しい GCC と標準ライブラリを使っていることが多いです。
一方、ローカル環境の MinGW は、

  • デフォルトが古い規格(例:C++98 相当)になっている
  • そもそも GCC/標準ライブラリが古くて <thread> 周りが弱い
  • PATH の先頭に「昔入れた別の g++」が残っていて、意図しないコンパイラが動いている

といった理由で差が出ます。特に最後の「別の g++ が動いている」は、本人が気づきにくい地雷です。

まずは現状確認:今動いている g++ を特定する

設定を直す前に、最初にやるべきことは「いま VS Code やターミナルが使っている g++ が何者か」を確定させることです。

コマンドで確認する

VS Code のターミナル(PowerShell / CMD)で次を実行します。

g++ --version
where g++

g++ --version で GCC の世代感が分かり、where g++ で “どのパスの g++ が呼ばれているか” が一覧で出ます。
ここで複数行出る場合は要注意で、VS Code のビルドが「自分の想定とは別の g++」を使っていることがよくあります。

規格が効いているかを確認する

次のコードで、コンパイル時の __cplusplus(規格の目安)を表示できます。

#include <iostream>

int main() {
std::cout << __cplusplus << "\n";
} 

出力値の目安は次の通りです。

__cplusplus の値だいたいの規格意味
199711LC++98/03この状態だと <thread> は基本的に使えない。まず規格オプションが必要
201103LC++11<thread> を使う最低ライン。古い MinGW だと実装が弱い場合も
201402LC++14実用上はこの辺以上が安心
201703LC++17近年の標準的な環境
202002LC++20今回はこの設定を推奨(環境差でハマりにくい)

もし 199711L が出ているなら、ほぼ確実に「規格が古い」が原因です。次の章の設定を優先してください。

対処の第一優先:C++20 を有効化してビルドする

<thread> は C++11 からの機能です。つまり、最小でも -std=c++11 が必要です。
ただし Windows の MinGW 環境は配布物や設定が混在しがちなので、記事としては 最初から -std=c++20 を明示するのが安全です(問題の切り分けも簡単になります)。

コマンドラインでの基本形

まずは VS Code を介さず、手打ちで通る形を作ると早いです。

g++ main.cpp -std=c++20 -O2 -Wall -Wextra -pedantic -o app.exe

ここで通れば、あとは VS Code の tasks.json に同じオプションを入れるだけです。

VS Code の tasks.json に -std=c++20 を入れる

VS Code の「タスクでビルド」や拡張機能からビルドしている場合、実体は tasks.json の引数です。典型例を載せます(必要最低限の形)。

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build (g++)",
      "type": "shell",
      "command": "g++",
      "args": [
        "-std=c++20",
        "-O2",
        "-Wall",
        "-Wextra",
        "-pedantic",
        "${file}",
        "-o",
        "${fileDirname}\\${fileBasenameNoExtension}.exe"
      ],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "problemMatcher": [
        "$gcc"
      ]
    }
  ]
}

ポイントは、必ず args に -std=c++20 を入れることです。
「設定したつもり」でも、別タスクを実行していたり、Code Runner の設定が別にあったりすると、オプションが付かないままビルドされてハマります。

gnu++20 と c++20 はどちらが良いか

-std=c++20 は純粋な標準準拠寄り、-std=gnu++20 は GCC 拡張も許可するモードです。
Windows の現場だと、外部ライブラリや環境依存コードの都合で gnu++20 が必要になるケースもありますが、<thread> の問題自体はどちらでも解決します。迷うならまず -std=c++20 でOKです。

規格を上げてもダメなとき:MinGW が古い可能性が高い

-std=c++20 を付けても std::thread が “存在しない扱い” のままなら、MinGW(GCC/標準ライブラリ)が古い可能性が高いです。
特に、昔からある「MinGW(mingw.org 系)」を使っていると、C++11 以降の機能が弱い、または更新が止まっていてハマりやすいです。

MinGW と MinGW-w64 の違いをざっくり掴む

系統特徴スレッド周りの期待値おすすめ度
古い MinGW(いわゆる mingw.org 系)昔からある。環境によって情報が混在しやすい<thread> 周りでハマりやすい避けたい
MinGW-w64 系64bit/32bit を含み、更新が活発な配布物が多い比較的安定。winpthread を含む構成も多い推奨

「MinGW を入れた」と言っていても、実際には複数の配布物が混ざっていることがあります。まずは where g++ の出力で、どのディレクトリの g++ を使っているかを確認してください。

MinGW を更新する現実的な選択肢

更新方法はいくつかありますが、共通して重要なのは「更新後に VS Code が新しい g++ を確実に使う状態にする」ことです。更新しても PATH が古いままだと、症状が変わりません。

選択肢の例

  • MinGW-w64 を含む配布物へ切り替える(例:MSYS2 系、WinLibs 系など)
  • 古い MinGW を PATH から外す(優先順位の問題を潰す)
  • VS Code のタスクが参照する g++ を固定する(フルパス指定)

特に手堅いのは、タスクの command を g++ ではなく、フルパスにする方法です。これなら PATH の混乱に強くなります。

"command": "C:\\msys64\\mingw64\\bin\\g++.exe"

このように指定しておけば、他に古い g++ が残っていても、ビルドだけは確実に狙ったコンパイラで実行できます。

更新後に必ずやるチェック

更新した直後は、次のチェックを必ず行ってください。

チェック項目確認方法狙い
VS Code のターミナルで新しい g++ が見えているwhere g++ / g++ --versionPATH の優先順位ミスを潰す
ビルドタスクが同じ g++ を使っているtasks.json をフルパス指定、または task 実行ログを確認ターミナルとビルドで別物を使っている事故を潰す
-std=c++20 が実際に付いているビルド出力にコマンドラインを出す設定にする「設定したつもり」を潰す

リンクエラーに変わった場合の話:-pthread と winpthread

今回の相談は「定義されていない」という コンパイルエラーが中心ですが、規格や MinGW を整えると、症状が一段階進んで「未定義参照」つまり リンクエラーに変わることがあります。

代表例としては次のようなパターンです。

  • undefined reference to ... が出る
  • std::thread は見えるようになったが、リンクで落ちる

この場合、環境によっては -pthread を付けることで解決します。まずは次の形を試します。

g++ main.cpp -std=c++20 -O2 -Wall -Wextra -pthread -o app.exe

ポイント

  • -pthread は「スレッド利用を前提にビルド・リンクする」ためのオプションで、環境によって必要になります
  • Windows の MinGW-w64 では内部的に winpthread を使う構成があり、ここで差が出ることがあります
  • ただし、今回の主症状が “宣言が見えない” 場合は、まず -std と MinGW 更新が先です

もし -pthread を足しても解決しない場合は、そもそも別の標準ライブラリや別の g++ を使っている(混在している)可能性が高いので、再度 where g++ に戻って確認してください。

エラー文から逆引きする早見表

ハマりやすいエラーと対処の対応表です。まずはここで自分の症状の位置づけを掴むと早いです。

エラー例段階よくある原因優先対処
‘thread’ is not a member of ‘std’コンパイルC++11以降になっていない/ヘッダを include していない#include <thread> と -std=c++20
‘this_thread’ has not been declaredコンパイル規格が古い/MinGW が古い/std::this_thread の名前空間ミス-std=c++20、改善しなければ MinGW 更新
this_thread was never definedコンパイル規格が古い・標準ライブラリが古い・環境混在__cplusplus を確認し、-std と MinGW-w64 化
undefined reference to ... std::thread ...リンクスレッドライブラリのリンク不足(環境差)-pthread を追加
VS Code は補完できるのにビルドだけ失敗設定IntelliSense と tasks のコンパイラが別tasks の g++ を固定し、IntelliSense 側も合わせる

動作確認に使える最小サンプル

切り分けでは「自分のプロジェクト」ではなく、まず最小コードで通るかを見るのが最短です。次のコードは std::thread と std::this_thread::sleep_for の両方を使います。

#include &lt;iostream&gt;
#include &lt;thread&gt;
#include &lt;chrono&gt;

int main() {
    std::cout &lt;&lt; "start\n";

    std::thread t([]{
        std::cout &lt;&lt; "worker: sleep...\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(300));
        std::cout &lt;&lt; "worker: wake\n";
    });

    t.join();
    std::cout &lt;&lt; "done\n";
}

コンパイル例はこれです。

g++ main.cpp -std=c++20 -O2 -Wall -Wextra -pedantic -pthread -o app.exe

この最小サンプルが通れば、環境として <thread> は使える状態です。あとは自分のプロジェクト側の設定(ビルド手順や CMake、タスク)に原因が残っています。

VS Code でありがちな落とし穴

VS Code は「補完」と「ビルド」が別設定になりやすいのが難点です。よくある落とし穴をまとめます。

補完が通るのにビルドが落ちる

これは、IntelliSense(C/C++ 拡張)が参照しているコンパイラと、tasks.json の g++ が別物になっているケースが多いです。

  • IntelliSense は新しい MinGW-w64 を参照
  • ビルドは PATH 上の古い MinGW を参照

というズレが起きると、「エディタでは問題なさそうなのにビルドだけ失敗」という状態になります。

対策としては次のどれかが効きます。

  • tasks.json の command を g++ のフルパスにする
  • Windows の環境変数 PATH を整理して、古い MinGW を外す
  • VS Code の設定や拡張機能で、使用コンパイラを統一する

Code Runner を使っていてオプションが付いていない

Code Runner はワンクリックで実行できて便利ですが、デフォルト設定だと -std=c++20 が付かず、古い規格でコンパイルされることがあります。
この場合は「タスクでビルド+実行」に寄せるか、Code Runner 側の設定で -std=c++20 を付与してください。

複数ファイルのときに ${file} だけをビルドしている

スレッドの問題とは別件ですが、プロジェクトが複数ファイルになっているのに tasks.json が ${file} だけをコンパイルしていて、別ファイルがリンクされていないことがあります。
この場合、エラーが <thread> とは違う形で出て混乱しやすいので、プロジェクトが大きい場合は CMake などのビルドシステムを使うのも有効です。

Code::Blocks での確認ポイント

Code::Blocks の場合も、根本は「規格」と「コンパイラの世代」です。確認ポイントは次の通りです。

  • 使用しているコンパイラがどこを指しているか(設定画面の Toolchain executables)
  • コンパイラオプションに -std=c++20(最低でも -std=c++11)を入れているか
  • 古い MinGW が同梱されている Code::Blocks をそのまま使っていないか

Code::Blocks は同梱 MinGW が古い構成もあり、その場合は更新した MinGW-w64 を明示的に紐づける必要があります。

現場でのおすすめ手順

最短で解決するための順番を、実務向けにまとめます。

順番やること判断基準
最初where g++ と g++ --version で実体を特定複数出たら混在の可能性大
次最小サンプルを -std=c++20 付きでビルド通れば環境はOK、プロジェクト設定へ
通らないMinGW を MinGW-w64 系へ更新更新後も where g++ を再確認
リンクで落ちる-pthread を追加未定義参照ならこの段階

まとめ

  • <thread> が「定義されていない」系のエラーは、まず C++11以降の有効化を疑う
  • VS Code では tasks.json に -std=c++20 を入れるのが定番で、最も再現性が高い
  • それでも直らないなら、MinGW が古い可能性が高いので MinGW-w64 系へ更新する
  • 症状がリンクエラーに変わったら -pthread を試す
  • 更新しても直らないときは、ほぼ確実に 別の g++ を使っているので where g++ に戻る

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次