C++-Parallelprogrammierung (2): Übergabe von Parametern an Thread-Funktionen

Übergeben Sie Parameter an die Thread-Funktion

Hauptsächlich in 3 Situationen unterteilt

  1. Gewöhnliche Funktion
  2. Klassenmitgliedsfunktion
  3. Der Parameter ist ein intelligenter Zeiger

Besonderes Augenmerk sollte darauf gelegt werden, dass der Thread über internen Speicherplatz verfügt . Die Parameter werden standardmäßig als temporäre Variablen kopiert und die temporäre Variable wird dann als R-Wert an die Funktion oder das aufrufbare Objekt im neuen Thread übergeben

Gewöhnliche Funktionsparameterübergabe

#include <iostream>
#include <thread>
#include <string.h>
using namespace std;

// void myPrint(string& t_)
// void myPrint(const string &t_)
void myPrint(string&& t_)
{
    
    
		t_ = "Ouch!";
    cout << "t_ location:" << &t_ << endl;
    cout << "myPrint:" << t_ << endl;
}

int main()
{
    
    
    char buff[]="Watch out!";
    string text = "Hello C++!";
    cout << "text location:" << &text << endl;
    cout << "buff location:" << &buff << endl;
		cout << "更改前text:" << text << endl;

    // thread t(myPrint, ref(text));
    thread t(myPrint, text);
    t.join();
    // t.detach();

		cout << "更改后text:" << text << endl;	
	
    cout << "main end!" << endl;

    return 0;
}

wichtiger Punkt:

1. Da es als R-Wert an die Funktion übergeben wird, sind die folgenden gewöhnlichen Referenzen nicht möglich und die Kompilierung wird nicht erfolgreich sein

void myPrint(string& t_)

Daher können nur zwei andere Referenzmethoden verwendet werden

2. Der Parameter wurde vor der Übergabe einmal kopiert, sodass die Referenz die Adresse der temporären Variablen annimmt und die Änderung der Funktion keine Auswirkungen auf den tatsächlichen Parameter hat. Führen Sie das obige Programm aus und geben Sie es aus

text location:0x7ffd5d2f84d0
buff location:0x7ffd5d2f84fd
更改前text:Hello C++!
t_ location:0x55dbf3e3e288
myPrint:Ouch!
更改后text:Hello C++!
main end!

Es wird festgestellt, dass die Adresse unterschiedlich ist und sich der Inhalt des Textes nicht geändert hat, sodass dies als falscher Verweis verstanden werden kann

Wenn Parameter als Referenz übergeben werden müssen, müssen sie wie folgt mit der Funktion std::ref( ) umschlossen werden, die der Funktion std::bind( ) ähnelt:

thread t(myPrint, ref(text));

Ausgabe nach dem Ausführen

text location:0x7ffcaaa3e6f0
buff location:0x7ffcaaa3e71d
更改前text:Hello C++!
t_ location:0x7ffcaaa3e6f0
myPrint:Ouch!
更改后text:Ouch!
main end!

Beachten Sie, dass die Funktionsdeklaration an dieser Stelle lautet

void myPrint(string& t_)

Zu diesem Zeitpunkt handelt es sich um eine L-Wert-Referenz, die wir normalerweise verstehen

Klassenmemberfunktion, die Parameter übergibt

Es kann in zwei Fälle unterteilt werden, je nachdem, ob die Mitgliedsfunktion eine statische Mitgliedsfunktion ist

1. Statische Mitgliedsfunktionen

#include <iostream>
#include <thread>
#include <string.h>
using namespace std;

class A
{
    
    
public:
    A(int a):m_a(a)
    {
    
    
        cout << "A 构造函数 。。。" << endl;
    }
    A(const A& a):m_a(a.m_a)
    {
    
    
        cout << "A 拷贝构造函数 。。。" << endl;
    }

    void operator()(){
    
    }

    static void printtext(string& t_)
    // void printtext(const string& t_)
    {
    
    
        t_ = "Ouch!";
        cout << "t_ location:" << &t_ << endl;
        cout << "t_:" << t_ << endl;
    }

    ~A(){
    
    cout << "A 析构函数 。。。" << endl;}
public:
    int m_a;
};

int main()
{
    
    
    char buff[]="Watch out!";
    string text = "Hello C++!";
    cout << "text location:" << &text << endl;
    cout << "buff location:" << &buff << endl;
    cout << "更改前text:" << text << endl;

    A A1(5);
    // thread t(A1);
    // thread t(&A::printtext,&A1,text);
    thread t(&A::printtext,ref(text));
    t.join();
    // t.detach();

    cout << "更改后text:" << text << endl;
    
    cout << "main end!" << endl;

    return 0;
}

Da sich die statische Mitgliedsfunktion im globalen Bereich im Speicher befindet, gehört sie zur Klasse und nicht zum Objekt der Klasse. Daher reicht es aus, anzugeben, dass die Funktion im Gültigkeitsbereich der Klasse liegt

thread t(&A::printtext,ref(text));

Zu diesem Zeitpunkt hat die Verwendung des Adresszeichens keine Auswirkung, und Folgendes ist ebenfalls möglich

thread t(A::printtext,ref(text));

Die Ausgabe ist wie folgt:

text location:0x7ffdda801e90
buff location:0x7ffdda801ebd
更改前text:Hello C++!
t_ location:0x7ffdda801e90
t_:Ouch!
更改后text:Ouch!
main end!

2. Nicht statische Mitgliedsfunktionen

Wenn Sie zu diesem Zeitpunkt eine Mitgliedsfunktion einer bestimmten Klasse als Thread-Funktion festlegen möchten, sollten Sie einen Funktionszeiger übergeben, der auf die Mitgliedsfunktion zeigt, und auch einen Objektzeiger wie folgt angeben:

thread t(&A::printtext,&A1,text);

Es gibt eine sehr bemerkenswerte Stelle, es gibt zwei Adresssymbole, wenn das erste entfernt wird, wird ein Fehler gemeldet

/home/prejudice/Cplus_learning/src/thread_02.cpp:54:17: error: invalid use of non-static member function ‘void A::printtext(std::__cxx11::string&&)
     thread t(A::printtext,&A1,text);

Daher muss das erste Adresssymbol reserviert werden, dann schauen Sie sich das zweite an

Wenn das & des zweiten Parameters entfernt wird, sieht die laufende Ausgabe wie folgt aus:

text location:0x7ffd84776370
buff location:0x7ffd8477639d
更改前text:Hello C++!
A 构造函数 。。。
A 拷贝构造函数 。。。
A 拷贝构造函数 。。。
A 析构函数 。。。
t_ location:0x559be66f7288
t_:Ouch!
A 析构函数 。。。
更改后text:Hello C++!
main end!
A 析构函数 。。。

Warum gibt es drei Aufbauten und Zerstörungen? So verstehe ich es

text location:0x7ffd84776370
buff location:0x7ffd8477639d
更改前text:Hello C++!
A 构造函数 。。。          //main中A1的构造
A 拷贝构造函数 。。。      //拷贝构造一个临时对象
A 拷贝构造函数 。。。      //将该临时对象拷贝到printtext函数中,作为该函数内的局部变量
A 析构函数 。。。          //临时对象使用完毕立即释放
t_ location:0x559be66f7288
t_:Ouch!
A 析构函数 。。。          //printtext函数运行结束释放栈区上的数据
更改后text:Hello C++!
main end!
A 析构函数 。。。          //mian结束调用A1的析构

Wenn Sie die &-Ausgabe des zweiten Parameters beibehalten, gehen Sie wie folgt vor

text location:0x7ffe6078fd40
buff location:0x7ffe6078fd6d
更改前text:Hello C++!
A 构造函数 。。。
t_ location:0x55af5cc36288
t_:Ouch!
更改后text:Hello C++!
main end!
A 析构函数 。。。

Es ist ersichtlich, dass die Hauptfunktion nur einmal erstellt wird, sodass keine zwei Kopien erforderlich sind, was die Betriebseffizienz verbessert

Daher wird empfohlen, Funktionszeiger und Objektzeiger gleichzeitig zu übergeben

Achten Sie auch hier auf die wahren und falschen Bezüge der Parameter

Der Parameter ist ein intelligenter Zeiger

Es gibt drei Arten von Smart Pointern:

  1. Exklusiver Zeiger – unique_ptr
  2. Gemeinsamer Zeiger – shared_ptr
  3. Schwacher Zeiger – schwacher_ptr

Hier sprechen wir nur von exklusiven Zeigern und gemeinsam genutzten Zeigern als Parameter, da schwache Zeiger in den Codes, die ich bisher gelesen habe, selten zu sehen sind

Sie können zunächst Ihr Wissen auffüllen und dann den folgenden Inhalt lesen

http://c.biancheng.net/view/1478.html

unique_ptr als Parameter

#include <iostream>
#include <thread>
#include <string.h>
#include <memory>
using namespace std;

// void myPrint(string& t_)
// void myPrint(const string &t_)
// void myPrint(string&& t_)
void myPrint(unique_ptr<string> t_)
//void myPrint(shared_ptr<string> t_)
{
    
    
    *t_ = "Ouch!";
    cout << "t_ location:" << &t_ << endl;
    cout << "myPrint:" << *t_ << endl;
}

int main()
{
    
    
    // string text = "Hello C++!";
    // unique_ptr<string> text(new string);
    unique_ptr<string> text = make_unique<string>("Hello C++!");
    // shared_ptr<string> text = make_shared<string>("Hello C++!");
    cout << "text location:" << &text << endl;
    cout << "更改前text:" << *text << endl;

    thread t(myPrint,move(text));
    t.join();
    // t.detach();

    // cout << "更改后text:" << *text << endl;
    
    cout << "main end!" << endl;

    return 0;
}

Ausgabe ausführen:

text location:0x7ffd55a3c1e8
更改前text:Hello C++!
t_ location:0x7f8bb48e8dc0
myPrint:Ouch!
main end!

wichtiger Punkt:

1. Verwenden Sie die Verschiebungsfunktion, um den Besitz des dynamischen Objekts auf den Thread zu übertragen. Nach der Übertragung wird der Text zu einem NULL-Zeiger, sodass Sie einen Kommentar abgeben müssen

// cout << "更改后text:" << *text << endl;

Andernfalls wird nach der Ausführung ein Segmentfehler angezeigt und der Kern wird ausgegeben

2. make_unique ist im C++14-Standard enthalten, daher müssen Sie CMakeLists.txt ändern

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread")

Andernfalls wird beim Kompilieren ein Fehler gemeldet

error: ‘make_unique’ was not declared in this scope
     unique_ptr<string> text = make_unique<string>();

shared_ptr ist ein Parameter

#include <iostream>
#include <thread>
#include <string.h>
#include <memory>
using namespace std;

// void myPrint(string& t_)
// void myPrint(const string &t_)
// void myPrint(string&& t_)
// void myPrint(unique_ptr<string> t_)
void myPrint(shared_ptr<string> t_)
{
    
    
    *t_ = "Ouch!";
    cout << "t_ location:" << &t_ << endl;
    cout << "myPrint:" << *t_ << endl;
}

int main()
{
    
    
    // string text = "Hello C++!";
    // unique_ptr<string> text(new string);
    // unique_ptr<string> text = make_unique<string>("Hello C++!");
    shared_ptr<string> text = make_shared<string>("Hello C++!");
    cout << "text location:" << &text << endl;
    cout << "更改前text:" << *text << endl;

    thread t(myPrint, text);
    // thread t(myPrint,move(text));
    t.join();
    // t.detach();

    cout << "更改后text:" << *text << endl;
    
    cout << "main end!" << endl;

    return 0;
}

Da die shared_ptr-Zeiger alle auf dieselbe Blockadresse zeigen, kann Text weiterhin im Hauptblock ausgedruckt werden

text location:0x7fffc22c9410
更改前text:Hello C++!
t_ location:0x7fd464a9bdc0
myPrint:Ouch!
更改后text:Ouch!
main end!

Verwenden Sie zum Testen auch die Memberfunktion der Klasse

#include <iostream>
#include <thread>
#include <string.h>
#include <memory>
using namespace std;

class A
{
    
    
public:
    A(int a) :m_a(a)
    {
    
    
        cout << "A 构造函数 。。。" << endl;
    }
    A(const A& a) :m_a(a.m_a)
    {
    
    
        cout << "A 拷贝构造函数 。。。" << endl;
    }

    void operator()() {
    
    }

    //void printtext(string& t_)
    // void printtext(const string& t_)
    void printtext(shared_ptr<string> t_)
    {
    
    
        *t_ = "Ouch!";
        cout << "t_ location:" << &t_ << endl;
        cout << "t_:" << *t_ << endl;
    }

    ~A() {
    
     cout << "A 析构函数 。。。" << endl; }
public:
    int m_a;
};

int main()
{
    
    
    // string text = "Hello C++!";
    // unique_ptr<string> text(new string);
    // unique_ptr<string> text = make_unique<string>("Hello C++!");
    shared_ptr<string> text = make_shared<string>("Hello C++!");
    cout << "text location:" << &text << endl;
    cout << "更改前text:" << *text << endl;

    A A1(5);
    thread t(&A::printtext, &A1, text);
    t.join();

    cout << "更改后text:" << *text << endl;

    cout << "main end!" << endl;

    return 0;
}

ausdrucken:

text location:0098FC38
更改前text:Hello C++!
A 构造函数 。。。
t_ location:00AFFCC4
t_:Ouch!
更改后text:Ouch!
main end!
A 析构函数 。。。

Mir ist aufgefallen, dass die Position von T_ unabhängig von der Position des Texts, unabhängig davon, ob es sich um eine gewöhnliche Funktion oder eine Mitgliedsfunktion handelt, sich von der Textposition unterscheidet und der Text schließlich erfolgreich geändert werden kann. Ich muss über die Leistungsfähigkeit von C++ seufzen

Aus diesem Grund handelt es sich möglicherweise um eine relativ niedrige Logik. Wenn Sie interessiert sind, können Sie es selbst lernen.

おすすめ

転載: blog.csdn.net/Solititude/article/details/131738709