C ++でのスレッドの簡単な例


391

C ++で2つの(オブジェクト指向)スレッドを開始する簡単な例を誰かが投稿できますか?

Cスタイルのスレッドライブラリを呼び出すのではなく、runメソッド(または類似の何か)を拡張できる実際のC ++スレッドオブジェクトを探しています。

私は、OS固有の要求は省略しました。返答する人はだれでもクロスプラットフォームライブラリを使用して返信することを期待しています。私は今それを明示しているだけです。


回答:


561

スレッドに実行させる関数を作成します。例:

void task1(std::string msg)
{
    std::cout << "task1 says: " << msg;
}

次に、thread最終的に上記の関数を呼び出すオブジェクトを次のように作成します。

std::thread t1(task1, "Hello");

(クラス#include <thread>にアクセスする必要がありますstd::thread

コンストラクターの引数は、スレッドが実行する関数で、その後に関数のパラメーターが続きます。スレッドは構築時に自動的に開始されます。

後で関数の実行が完了するまでスレッドを待機したい場合は、次を呼び出します。

t1.join(); 

(結合とは、新しいスレッドを呼び出したスレッドが、新しいスレッドの実行が完了するのを待ってから、それ自体の実行を継続することを意味します)。


コード

#include <string>
#include <iostream>
#include <thread>

using namespace std;

// The function we want to execute on the new thread.
void task1(string msg)
{
    cout << "task1 says: " << msg;
}

int main()
{
    // Constructs the new thread and runs it. Does not block execution.
    thread t1(task1, "Hello");

    // Do other things...

    // Makes the main thread wait for the new thread to finish execution, therefore blocks its own execution.
    t1.join();
}

std :: threadの詳細はこちら

  • GCCでは、でコンパイルし-std=c++0x -pthreadます。
  • これは、コンパイラがこの(C ++ 11)機能をサポートしていれば、どのオペレーティングシステムでも機能します。

4
@ Preza8 VS10は、C ++ 11の多くの機能をサポートしていません。VS12およびVS13はスレッドをサポートします。
jodag 2014年

3
コメントの「GCCバージョン4.7以下-std=c++0x(の代わりに-std=c++0x)を使用」では、2番目の「c ++ 0x」を「c ++ 11」にする必要があると思いますが、編集が小さすぎるため変更できません。
zentrunix 2014年

1
@MasterMastic std :: thread t1(task1、 "Hello")の代わりにstd :: thread t1(&task1、 "Hello")を使用して関数の参照を渡すと、どのような違いがありますか?この場合、関数をポインタとして宣言する必要がありますか?
user2452253 2014年

3
@ user2452253「task1」を渡す場合は、実行する関数へのポインタを渡します(これは良いことです)。「&task1」を渡すと、ポインタを関数のポインタに渡し、結果はおそらくそれほどきれいではなく、あまり定義されません(ランダムな命令を次々に実行しようとするようなものです。正しい確率では、地獄へのゲートウェイを開きます)。あなたは本当に関数ポインタ(関数が始まるアドレスの値を持つポインタ)を渡したいだけです。それでも問題が解決しない場合は、お知らせください。幸運を祈ります!
MasterMastic 2014年

2
@curiousguyまあ、それを行う正しい方法は、実行したい関数のポインターを渡すことです。この場合、関数はtask1です。したがって、関数ポインタもで表されtask1ます。しかし、私は私が間違っていたと考えているので、これを育ててくれてありがとう、それはと同等だ&task1、それは、私は、関数のポインタにそのポインタを推測もしそうなら、あなたが(書き込みに選択形成している問題ではないですので、&&task1- それは悪いだろう)。関連質問
MasterMastic 2018

80

まあ、C ++ std::threadはc ++ 0xでストックモデルを指定しただけなので、技術的にはそのようなオブジェクトはすべてCスタイルのスレッドライブラリ上に構築されてしまいます。問題はやや体系的であり、技術的には既存のc ++メモリモデルは、すべての「前に起こる」ケースに対して明確に定義されたセマンティクスを可能にするほど厳密ではありません。Hans Boehmはしばらく前にこのトピックに関する論文を書いており、このトピックに関するc ++ 0x標準を打ち出すのに役立ちました。

http://www.hpl.hp.com/techreports/2004/HPL-2004-209.html

そうは言っても、実際には問題なく動作するクロスプラットフォームのスレッドC ++ライブラリがいくつかあります。インテルスレッドビルディングブロックには、c ++ 0x標準に非常に近いtbb :: threadオブジェクトが含まれており、Boostには、同じことを行うboost :: threadライブラリがあります。

http://www.threadingbuildingblocks.org/

http://www.boost.org/doc/libs/1_37_0/doc/html/thread.html

boost :: threadを使用すると、次のようになります。

#include <boost/thread.hpp>

void task1() { 
    // do stuff
}

void task2() { 
    // do stuff
}

int main (int argc, char ** argv) {
    using namespace boost; 
    thread thread_1 = thread(task1);
    thread thread_2 = thread(task2);

    // do other stuff
    thread_2.join();
    thread_1.join();
    return 0;
}

8
ブーストスレッドはすばらしい-私の唯一の問題は、プライベートクラスメンバーであるため、実際に基盤となるスレッドハンドルにアクセスできなかった(前回使用したとき)ことでした。win32にはスレッドハンドルが必要なものがたくさんあるので、ハンドルを公開するために微調整しました。
オリオンエドワーズ

4
boost :: threadのもう1つの問題は、私が覚えているように、新しいスレッドのスタックサイズを自由に設定できないことです。これは、残念ながらc ++ 0x標準には含まれていない機能です。
エドワードKMETT 2008年

そのコードは私にこの行のboost :: noncopyable例外を与えます:thread thread_1 = thread(task1); 古いバージョン(1.32)を使用している可能性があります。
フランク

task1はこのスコープで宣言されていませんか?
Jake Gaston、

20

POSIXオペレーティングシステム用のPOSIXライブラリもあります。 互換性を確認する

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>

void *task(void *argument){
      char* msg;
      msg = (char*)argument;
      std::cout<<msg<<std::endl;
}

int main(){
    pthread_t thread1, thread2;
    int i1,i2;
    i1 = pthread_create( &thread1, NULL, task, (void*) "thread 1");
    i2 = pthread_create( &thread2, NULL, task, (void*) "thread 2");

    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    return 0;

}

-lpthreadでコンパイルする

http://en.wikipedia.org/wiki/POSIX_Threads


18
#include <thread>
#include <iostream>
#include <vector>
using namespace std;

void doSomething(int id) {
    cout << id << "\n";
}

/**
 * Spawns n threads
 */
void spawnThreads(int n)
{
    std::vector<thread> threads(n);
    // spawn n threads:
    for (int i = 0; i < n; i++) {
        threads[i] = thread(doSomething, i + 1);
    }

    for (auto& th : threads) {
        th.join();
    }
}

int main()
{
    spawnThreads(10);
}

13

新しいスレッドで独自のインスタンスメソッドの1つを呼び出すC ++クラスの例を検索すると、この質問が出てきますが、そのようにこれらの回答を使用することはできませんでした。これを行う例を次に示します。

Class.h

class DataManager
{
public:
    bool hasData;
    void getData();
    bool dataAvailable();
};

Class.cpp

#include "DataManager.h"

void DataManager::getData()
{
    // perform background data munging
    hasData = true;
    // be sure to notify on the main thread
}

bool DataManager::dataAvailable()
{
    if (hasData)
    {
        return true;
    }
    else
    {
        std::thread t(&DataManager::getData, this);
        t.detach(); // as opposed to .join, which runs on the current thread
    }
}

この例は、ミューテックスやロックには入りません。


2
これを投稿してくれてありがとう。インスタンスメソッドでスレッドを呼び出す一般的な形式は次のようになります。std :: thread t(&Foo :: Run、&f、args ...); (Fooはメンバー関数として「Run()」を持つクラスです)。
ジェイエルストン

これを投稿してくれてありがとう。すべてのスレッドの例がグローバル関数を使用する理由を真剣に理解していません。
hkBattousai

9

グローバルネームスペースに個別の関数が必要でない限り、スレッドを作成するためにラムダ関数を使用できます。

ラムダを使用してスレッドを作成する主な利点の1つは、ローカルパラメーターを引数リストとして渡す必要がないことです。同じためにキャプチャリストを使用でき、ラムダのクロージャプロパティがライフサイクルを処理します。

これがサンプルコードです

int main() {
    int localVariable = 100;

    thread th { [=](){
        cout<<"The Value of local variable => "<<localVariable<<endl;
    }}

    th.join();

    return 0;
}

はるかに、C ++ラムダは、特に単純なスレッド関数用のスレッドを作成する最良の方法であることがわかりました


8

使用するライブラリに大きく依存します。たとえば、wxWidgetsライブラリを使用する場合、スレッドの作成は次のようになります。

class RThread : public wxThread {

public:
    RThread()
        : wxThread(wxTHREAD_JOINABLE){
    }
private:
    RThread(const RThread &copy);

public:
    void *Entry(void){
        //Do...

        return 0;
    }

};

wxThread *CreateThread() {
    //Create thread
    wxThread *_hThread = new RThread();

    //Start thread
    _hThread->Create();
    _hThread->Run();

    return _hThread;
}

メインスレッドがCreateThreadメソッドを呼び出す場合は、 "Entry"メソッドのコードの実行を開始する新しいスレッドを作成します。参加または停止するには、ほとんどの場合、スレッドへの参照を保持する必要があります。詳細はこちら:wxThreadのドキュメント


1
スレッドを削除するのを忘れました。おそらく、分離スレッドを作成するつもりでしたか?
aib 2008年

1
そうです、現在作業中のコードからコードを抽出しました。もちろん、後でそれを結合、停止、削除するために、スレッドへの参照がどこかに保存されています。ありがとう。:)
LorenzCK 2008年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.