1,创建线程并传递参数
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
void fun1(int iarg )
{
cout << " thread id: " << this_thread::get_id() <<" Arg : " << iarg << endl;
for (int i = 0; i < 10; i ++ )
{
cout << "11111111" << endl;
this_thread::sleep_for(chrono::seconds(2));
}
}
void fun2(int iarg )
{
cout << " thread id: " << this_thread::get_id() << " Arg : " << iarg << endl;
for (int i = 0; i < 10; i++ )
{
cout << "22222222" << endl;
this_thread::sleep_for(chrono::seconds(3));
}
}
int main(int argc, char * argv[])
{
int iarg = 7;
thread t1(fun1, iarg);
thread t2(fun2, iarg);
cout << "main thread" << endl;
return 0;
}
如上写的主函数运行时会报如下的错误,原因是在创建了线程后线程后,线程立即开始执行,但是主线程main()并没有停止脚步,仍然继续执行然后退出,此时t1,t2线程对象还是joinable的,线程仍然存在, 但是main线程已经销毁,所以会抛出异常。
std::thread::joinable
C++ Thread support library std::thread
bool joinable() const noexcept;
(since C++11)
Checks if the thread object identifies an active thread of execution. Specifically, returns true if get_id() != std::thread::id(). So a default constructed thread is not joinable.
A thread that has finished executing code, but has not yet been joined is still considered an active thread of execution and is therefore joinable.
Parameters
(none)
Return value
true if the thread object identifies an active thread of execution, false otherwise
Example
Run this code
#include <iostream>
#include <thread>
#include <chrono>
void foo()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main()
{
std::thread t;
std::cout << "before starting, joinable: " << std::boolalpha << t.joinable()
<< '\n';
t = std::thread(foo);
std::cout << "after starting, joinable: " << t.joinable()
<< '\n';
t.join();
std::cout << "after joining, joinable: " << t.joinable()
<< '\n';
}
Output:
before starting, joinable: false
after starting, joinable: true
after joining, joinable: false
2, thread::join
那么该如何保证子线程执行完了退出后再退出主线程呢?使用join接口可以解决上述问题,join的作用是让主线程等待直到该子线程执行结束,示例:
改为如下代码,则不会报异常
int main(int argc, char * argv[])
{
int iarg = 7;
thread t1(fun1, iarg);
thread t2(fun2, iarg);
cout << "t1 joinable : " << t1.joinable() << endl;
cout << "t2 joinable : " << t2.joinable() << endl;
t1.join();
t2.join();
cout << "main thread" << endl;
cout << "t1 joinable : " << t1.joinable() << endl;
cout << "t2 joinable : " << t2.joinable() << endl;
system("pause");
return 0;
}
输出结果
上图表明;main线程是等待子线程结束后才执行结束的。
thread::join()用来等待子线程结束。
thread::joinable()用来检测线程是否活跃。
注意:上面的打印没有按照期望的打印格式打印,原因是没有加锁。
3,std中的mutex
mutex有个缺点,就是如果mutex.unlock()在执行之前,程序抛出异常,那么该资源就不能够得到访问。
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
mutex g_mutex;
void fun1(int iarg )
{
g_mutex.lock();
cout << " thread id: " << this_thread::get_id() <<" Arg : " << iarg << endl;
g_mutex.unlock();
for (int i = 0; i < 2; i ++ )
{
g_mutex.lock();
cout << "11111111" << endl;
g_mutex.unlock();
this_thread::sleep_for(chrono::milliseconds(2));
}
}
void fun2(int iarg )
{
g_mutex.lock();
cout << " thread id: " << this_thread::get_id() << " Arg : " << iarg << endl;
g_mutex.unlock();
for (int i = 0; i < 2; i++ )
{
g_mutex.lock();
cout << "22222222" << endl;
g_mutex.unlock();
this_thread::sleep_for(chrono::milliseconds(3));
}
}
int main(int argc, char * argv[])
{
int iarg = 7;
thread t1(fun1, iarg);
thread t2(fun2, iarg);
g_mutex.lock();
cout << "t1 joinable : " << t1.joinable() << endl;
cout << "t2 joinable : " << t2.joinable() << endl;
g_mutex.unlock();
t1.join();
t2.join();
cout << "main thread" << endl;
cout << "t1 joinable : " << t1.joinable() << endl;
cout << "t2 joinable : " << t2.joinable() << endl;
system("pause");
return 0;
}
输出:打印是按照自己期望的格式打印的。
4,std::lock_guard
使用lock_guard则相对安全,它是基于作用域的,能够自解锁,当该对象创建时,它会像m.lock()一样获得互斥锁,当生命周期结束时,它会自动析构(unlock),不会因为某个线程异常退出而影响其他线程。
http://en.cppreference.com/w/cpp/thread/lock_guard
std::lock_guard
C++ Thread support library std::lock_guard
Defined in header <mutex>
template< class Mutex >
class lock_guard;
The class lock_guard is a mutex wrapper that provides a convenient RAII-style mechanism for owning a mutex for the duration of a scoped block.
When a lock_guard object is created, it attempts to take ownership of the mutex it is given. When control leaves the scope in which the lock_guard object was created, the lock_guard is destructed and the mutex is released.
The lock_guard class is non-copyable.
Template parameters
Mutex - the type of the mutex to lock. The type must meet the BasicLockable requirements
Member types
Member type Definition
mutex_type Mutex
Member functions
(constructor)
constructs a lock_guard, optionally locking the given mutex
(public member function)
(destructor)
destructs the lock_guard object, unlocks the underlying mutex
(public member function)
operator=
[deleted]
not copy-assignable
(public member function)
Example
Run this code
#include <thread>
#include <mutex>
#include <iostream>
int g_i = 0;
std::mutex g_i_mutex; // protects g_i
void safe_increment()
{
std::lock_guard<std::mutex> lock(g_i_mutex);
++g_i;
std::cout << std::this_thread::get_id() << ": " << g_i << '\n';
// g_i_mutex is automatically released when lock
// goes out of scope
}
int main()
{
std::cout << "main: " << g_i << '\n';
std::thread t1(safe_increment);
std::thread t2(safe_increment);
t1.join();
t2.join();
std::cout << "main: " << g_i << '\n';
}
Possible output:
main: 0
140641306900224: 1
140641298507520: 2
main: 2
4, std::thread::detach
detach 用于把线程对象和线程的执行函数分开。就是说线程对象即使已经销毁,线程也可以继续执行,同样也可以解决上面的问题。不过这样由于没有thread对象指向该线程而失去了对它的控制,当对象析构时线程会继续在后台执行,但是当主程序退出时并不能保证线程能执行完。如果没有良好的控制机制或者这种后台线程比较重要,最好不用detach而应该使用join。
int main(int argc, char * argv[])
{
int iarg = 7;
thread t1(fun1, iarg);
thread t2(fun2, iarg);
g_mutex.lock();
cout << "t1 joinable : " << t1.joinable() << endl;
cout << "t2 joinable : " << t2.joinable() << endl;
g_mutex.unlock();
t1.detach();
t2.detach();
g_mutex.lock();
cout << "main thread" << endl;
cout << "t1 joinable : " << t1.joinable() << endl; //此时返回0,因为detach(),所以该对象已经不负责fun1的管理。
cout << "t2 joinable : " << t2.joinable() << endl; //此时返回0
g_mutex.unlock();
system("pause");
return 0;
}
输出:
thread id: 8084 Arg : 7
thread id: 8608 Arg : 7
t1 joinable : 1
t2 joinable : 1
11111111
22222222
main thread
t1 joinable : 0
t2 joinable : 0
11111111
22222222
http://en.cppreference.com/w/cpp/thread/thread/detach
std::thread::detach
C++ Thread support library std::thread
void detach();
(since C++11)
Separates the thread of execution from the thread object, allowing execution to continue independently. Any allocated resources will be freed once the thread exits.
After calling detach *this no longer owns any thread.
Parameters
(none)
Return value
(none)
Postconditions
joinable is false
Exceptions
std::system_error if joinable() == false or an error occurs.
Example
Run this code
#include <iostream>
#include <chrono>
#include <thread>
void independentThread()
{
std::cout << "Starting concurrent thread.\n";
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Exiting concurrent thread.\n";
}
void threadCaller()
{
std::cout << "Starting thread caller.\n";
std::thread t(independentThread);
t.detach();
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Exiting thread caller.\n";
}
int main()
{
threadCaller();
std::this_thread::sleep_for(std::chrono::seconds(5));
}
Possible output:
Starting thread caller.
Starting concurrent thread.
Exiting thread caller. //执行该句时,相当于主线程退出
Exiting concurrent thread. //该句执行时,子线程已经结束。