C++11 – std::thread

C++ programlama dilinin en büyük eksikliklerinden biri de built-in concurrency desteğiydi. Aslında bu sorunu uzun zamandır C programcıları posix thread kütüphanesi ile çözüyordu. C++ programcıları ise boost kütüphanesinin bir parçası olan thread kütüphanesini kullandılar. C++11 ile artık dile multi-threading desteği boost kütüphanesinin boost::thread kütüphanesinin büyük bir kısmı miras alınarak dilin standardına eklendi.

C++ konferanslarında dinlediğim, boost::thread in yazarlarından Anthony Wiliams’ ın kitabını okuyarak edindiğim bazı bilgileri bu blogta türkçe kaynak olması amacıyla paylaşmayı uygun gördüm. Olabildiğince örneklendirerek anlamayı ve kullanım hatalarını en aza indirmeyi amaçlıyorum.

O zaman ilk olarak geleneksel ‘Hello World’ ü thread ile oluşturalım.

#include <iostream>
#include <thread>



using namespace std;

void threadFunc()
{
    cout << "Hello from Thread" << endl;
}


int main(int argc, char** argv) 
{
    thread th (threadFunc);
    
    
    th.join();

    return 0;
}

std isim alanı altında bulunan thread sınıfı görüldüğü üzere ctor fonksiyonuna thread de çalıştırılması düşünülen fonksiyonun adresi geçilerek inşaa edilir. Daha sonra ise ‘th’ isimli yeni bir thread oluşturan ana thread oluşturduğu threadin işinin bitmesini thread sınıfındaki ‘join’ fonksiyonunu çağırarak sağlar. Bu noktada ana thread bloke olur ve ‘th’ isimli threading işi bitene kadar bekler. Bu konuya ikinci bölümde daha detaylı ele alacağız.

Sadece fonksiyon göstericileri ile degil istenirse C++11 ile gelen özelliklerden biri olan lambda ifadeleri ve Functor (fonksiyon çağırma operatörü overload edilmiş nesne) nesneler ile de ctor çağırılabilir.

#include <iostream>
#include <thread>

using namespace std;

struct SFtor
{
    void operator ()()
    {
        cout << "Hello from Ftor" << endl;
    }
};

int main()
{
    SFtor sf;
    
    
   thread th([]() {
       
       cout << "Hello from Lambda" << endl;
   });
   
   thread th1(sf);
   
   
   th.join();
   th1.join();
   
   return 0;
}

Performans odaklı program yazıyorsanız functor kullanmanız lehinize olur inline olarak değerlendirilmelerinden ötürü daha hızlı işler. Tabi bu mesele standart olarak değerlendirmek mümkün değil, derleyici bağımlıdır.

Threadlere Parametre Geçmek
Thread sınıfı değişken parametreli şablon fonksiyonlarına (variadic templates) güzel bir örnektir. Bu sayede thread değişkenine geçilen fonksiyonunun parametresini thread sınıfının ctor ına 2. parametre olarak geçebilirsiniz.

#include <iostream>
#include <thread>

using namespace std;

struct SFtor
{
    void operator ()(string const &s)
    {
        cout << "Hello from Ftor " << s <<endl;
    }
};

void threadFunc(int a)
{
    cout << "Hello from traditional func " << a << endl;
}

int main()
{
    SFtor sf;
    
    
   thread th(threadFunc, 5);
   
   thread th1(sf, "cpp istanbul");
   
   
   th.join();
   th1.join();
   
   return 0;
}

Örneklerde görüldüğü gibi thread sınıfının ctorının ilk parametresinden sonra girilen argümanlar çağırılacak olan fonksiyon nesnesine parametre olarak geçiliyor. Yalnız burada dikkat edilmesi gereken noktalardan biri parametreler thread fonksiyonuna geçilirken kopyalanarak aktarılır. Eğer referans olarak geçmek istersek std::ref veya std::cref fonksiyonları kullanılır.

#include <iostream>
#include <thread>

using namespace std;


void threadFunc(int &a)
{
    cout << "thread: " << a << endl;
    a++;
}

int main()
{
   int a = 5;
    
   thread th(threadFunc, ref(a));
   
   th.join();
    
   cout << "main thread: " << a << endl;
    
   return 0;
}

Yukarıdaki örnekte de değişken threade referans olarak geçilerek fonksiyon gövdesinde bir arttırlıyor. Kodu çalıştırdığımızda sonuç olarak ekrana:

thread: 5
main thread: 6

yazacaktır.

Thread fonksiyonuna lambda ifadeleri, Functorlar ve normal fonksiyonlar haricinde bir sınıfın üye fonksiyonunu da geçebilirsiniz. Eğer daha önce std::bind fonksiyonunu kullandıysanız benzer bir sentaksa sahip olduğunu hemen farkedeceksiniz.

Örneğin, ilk parametreye üye fonksiyon adresi daha sonra ilgili sınıfın nesnesi daha sonra ise sırayla fonksiyona eğer varsa parametreler geçilir.

#include <iostream>
#include <thread>

using namespace std;

struct SMemFunc
{
    void foo(string &s)
    {
        s+= " istanbul";
    }

};



int main()
{
    SMemFunc mf;
    string s("cpp");
    
    cout << "before join s: " << s << endl;
    
    thread th(&SMemFunc::foo, mf, ref(s));
    
    th.join();
    
    cout << "after join s: " << s << endl;
     
   return 0;
}

Yukarıdaki örnek çalıştığında referans yoluyla SMemFunc sınıfına geçilen ‘s’ nesnesi fonksiyonda sonuna ‘istanbul’ eklenir. Kısacası çalıştırılan program ekrana:

before join s: cpp
after join s: cpp istanbul

yazdırılır.

Devam edecek…

Advertisements

5 thoughts on “C++11 – std::thread

  1. struct SMemFunc
    {
    static void foo(string &s)
    {
    s+= ” istanbul”;
    }

    };
    int main()
    {
    string s(“cpp”);

    cout << "before join s: " << s << endl;

    thread th(&SMemFunc::foo, ref(s));

    th.join();

    cout << "after join s: " << s << endl;

    return 0;
    }

    Son örneği yukarıdaki gibi (static function olacak biçimde ) yorumlarsak farkı ne olur acaba? Daha performanslı hale gelir mi?

    • Sanmıyorum, static fonksiyonlarda programın başlangıç zamanında yaratılırlar, sınıflarla mantıksal bir ilişki içerisindedirler aslında. Global normal bir fonksiyon ile static fonksiyon arasında pek bir fark olmayacakmış gibi geliyor.

  2. Elinize sağlık İslam Bey,
    Güzel bir yazı olmuş.
    std::asynch
    std::promise
    std::terminate
    std::mutex
    konularına gelecek yazınızda bahsetmeniz dileğiyle.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s