1. 程式人生 > >C++11多執行緒程式設計 第三章: 如何向執行緒傳參

C++11多執行緒程式設計 第三章: 如何向執行緒傳參

C++11 Multithreading – Part 3: Carefully Pass Arguments to Threads

Varun January 22, 2015 C++11 Multithreading – Part 3: Carefully Pass Arguments to Threads2018-08-18T15:14:54+00:00C++ 11c++11 ThreadsMultithreading 1 Comment

To Pass arguments to thread’s associated callable object or function just pass additional arguments to the std::thread constructor.
By default all arguments are copied into the internal storage of new thread.

Lets look at an example

Passing simple arguments to a std::thread in C++11

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <iostream>

#include <string>

#include <thread>

void threadCallback(int x, std::string str)

{

    std::cout<<"Passed Number = "<<x<<std::endl;

    std::cout<<"Passed String = "<<str<<std::endl;

}

int main()  

{

    int x = 10;

    std::string str = "Sample String";

    std::thread threadObj(threadCallback, x, str);

    threadObj.join();

    return 0;

}

 

How not to pass arguments to threads in C++11

Don’t pass addresses of variables from local stack to thread’s callback function. Because it might be possible that local variable in Thread 1 goes out of scope but Thread 2 is still trying to access it through it’s address.
In such scenario accessing invalid address can cause unexpected behaviour.
For example,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

#include <iostream>

#include <thread>

void newThreadCallback(int * p)

{

    std::cout<<"Inside Thread :  "" : p = "<<p<<std::endl;

    std::chrono::milliseconds dura( 1000 );

    std::this_thread::sleep_for( dura );

    *p = 19;

}

void startNewThread()

{

    int i = 10;

    std::cout<<"Inside Main Thread :  "" : i = "<<i<<std::endl;

    std::thread t(newThreadCallback,&i);

    t.detach();

    std::cout<<"Inside Main Thread :  "" : i = "<<i<<std::endl;

}

int main()

{

    startNewThread();

    std::chrono::milliseconds dura( 2000 );

    std::this_thread::sleep_for( dura );

    return 0;

}

Similarly be careful while passing pointer to memory located on heap to thread. Because it might be possible that some thread deletes that memory before new thread tries to access it.
In such scenario accessing invalid address can cause unexpected behaviour.
For example,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#include <iostream>

#include <thread>

void newThreadCallback(int * p)

{

    std::cout<<"Inside Thread :  "" : p = "<<p<<std::endl;

    std::chrono::milliseconds dura( 1000 );

    std::this_thread::sleep_for( dura );

    *p = 19;

}

void startNewThread()

{

    int * p = new int();

    *p = 10;

    std::cout<<"Inside Main Thread :  "" : *p = "<<*p<<std::endl;

    std::thread t(newThreadCallback,p);

    t.detach();

    delete p;

    p = NULL;

}

int main()

{

    startNewThread();

    std::chrono::milliseconds dura( 2000 );

    std::this_thread::sleep_for( dura );

    return 0;

}

 

How to pass references to std::thread in C++11

As arguments are copied to new threads stack so, if you need to pass references in common way i.e.

Check this,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <iostream>

#include <thread>

void threadCallback(int const & x)

{

    int & y = const_cast<int &>(x);

    y++;

    std::cout<<"Inside Thread x = "<<x<<std::endl;

}

int main()

{

    int x = 9;

    std::cout<<"In Main Thread : Before Thread Start x = "<<x<<std::endl;

    std::thread threadObj(threadCallback, x);

    threadObj.join();

    std::cout<<"In Main Thread : After Thread Joins x = "<<x<<std::endl;

    return 0;

}

Its output is

In Main Thread : Before Thread Start x = 9 
Inside Thread x = 10 
In Main Thread : After Thread Joins x = 9 

 

Even if threadCallback accepts arguments as reference but still changes done it are not visible outside the thread.
Its because x in the thread function threadCallback is reference to the temporary value copied at the new thread’s stack.

How to fix this ?

Using std::ref() i.e.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <iostream>

#include <thread>

void threadCallback(int const & x)

{

    int & y = const_cast<int &>(x);

    y++;

    std::cout<<"Inside Thread x = "<<x<<std::endl;

}

int main()

{

    int x = 9;

    std::cout<<"In Main Thread : Before Thread Start x = "<<x<<std::endl;

    std::thread threadObj(threadCallback,std::ref(x));

    threadObj.join();

    std::cout<<"In Main Thread : After Thread Joins x = "<<x<<std::endl;

    return 0;

}

Its output is

In Main Thread : Before Thread Start x = 9 
Inside Thread x = 10 
In Main Thread : After Thread Joins x = 10 
 

Assigning pointer to member function of a class as thread function:

Pass the pointer to member function as callback function and pass pointer to Object as second argument.

For example,

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#include <iostream>

#include <thread>

class DummyClass {

public:

    DummyClass()

    {}

    DummyClass(const DummyClass & obj)

    {}

    void sampleMemberFunction(int x)

    {

        std::cout<<"Inside sampleMemberFunction "<<x<<std::endl;

    }

};

int main() {

 

    DummyClass dummyObj;

    int x = 10;

    std::thread threadObj(&DummyClass::sampleMemberFunction,&dummyObj, x);

    threadObj.join();

    return 0;

}

通過這種方式, 就可以模擬Java中的Thread函式. 類似:

class MyThread{

void stop(); //裡面標記一個原子變數_stop;

void run(); // 在迴圈裡判斷_stop是否置為true, 如果為true, 則停止執行.

void start(){

       std::thread myThread(&MyThread::run, this); //建立子執行緒執行run函式.
        if (myThread.joinable()) {
           myThread.detach(); // 與建立函式的物件分離, 否則物件析構時, 會呼叫執行緒的terminate終止執行緒執行. 
        }

    }

}