C++ 11 中的thread

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. //该句执行时,子线程已经结束。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 创建一个基于对话框的应用程序。并增加如图所示控件;分别为3个进度条控件关联三个进度条类型的变量;并在对话框的初始化函数,设定进度条的范围;为编辑框关联一个整型的变量;为12个按钮添加消息处理函数; 2. 定义结构体:用做线程函数的参数传递 typedef struct Threadinfo{ CProgressCtrl *progress;//进度条对象 int speed; //进度条速度 int pos; //进度条位置 } thread,*lpthread; 3. 为对话框增加三个句柄,用于标识各个线程; HANDLE hThread1; //线程1线程句柄 HANDLE hThread2; //线程2线程句柄 HANDLE hThread3; //线程3线程句柄 在增加三个结构体类型的变量,用做线程函数的参数传递; HANDLE hThread1; //线程1线程句柄 HANDLE hThread2; //线程2线程句柄 HANDLE hThread3; //线程3线程句柄 4. 新增一个静态的全局变量,用于记录所有线程的状态:static int GlobalVar=10000; 5. 声明并编写线程函数,注意只能有一个参数,且函数的返回值类型也是固定的;函数名可以自定义; DWORD WINAPI ThreadFun(LPVOID pthread);//线程入口函数 6. 在启动按钮的消息处理函数编写如下代码: thread1.progress=&m_progress1;//进度条对象 thread1.speed=100;//速度 thread1.pos=0;//初始位置 hThread1=CreateThread(NULL,0,ThreadFun,&thread1;,0,0);//创建并开始线程 if (!hThread1) { MessageBox("创建线程失败"); } 7. 编写线程函数(一般是一个死循环,或者需要花费时间很长的算法!否者就失去了多线程的意义) DWORD WINAPI ThreadFun(LPVOID pthread) //线程入口函数 { lpthread temp=(lpthread)pthread;//参数强制转换为结构体类型 temp->progress->SetPos(temp->pos); //设置被传递过来的进度条的位置 while(temp->posspeed); /设置速度 temp->pos++; //增加进度 temp->progress->SetPos(temp->pos); //设置进度条的新位置 GlobalVar--; if(temp->pos==20) { temp->pos=0; //进度条满则归0 } } return true; } 8. 在挂起按钮函数,编写如下代码: if(SuspendThread(hThread1)==0xFFFFFFFF) { MessageBox("挂起失败!进程可能已经死亡或未创建!"); return; } 9. 在执行按钮函数,编写如下代码: if(ResumeThread(hThread1)==0xFFFFFFFF) { MessageBox("执行失败!进程可能已经死亡或未创建!"); return; } 10. 在停止按钮函数,编写如下代码: if(TerminateThread(hThread1,0))//前些终止线程 { CloseHandle(hThread1);//销毁线程句柄 } else { MessageBox("终止进程失败!"); } 11. 为应用程序添加WM_TIMER消息,实时更新全局变量的值到编辑框;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值