C++多线程(TODO)

入门

#include <iostream>
#include <thread>

void hello() //线程的起始函数
{
    std::cout << "Hello" << std::endl;
}

int main()
{
    std::thread t(hello); //子线程的起始函数在thread的构造函数中指明
    t.join(); //等待子线程结束
    return 0;
}

编译指令:

g++ -pthread test.cpp 

任何可调用类型都适用与std::thread

future等待一次性事件发生

future与async的使用

示例1:

int find_answer() {
    return 123;
}

void do_other_thing() {
    this_thread::sleep_for(chrono::seconds(3));
}

int main()
{
    future<int> ans = async(find_answer);
    do_other_thing();
    cout << ans.get() << endl;
    return 0;
}

示例2:

class X
{
public:
    int exe(int& a)
    {
        a += 10;
        return a;
    }
};

void do_other_thing()
{
    this_thread::sleep_for(chrono::seconds(1));
}

int main()
{
    X x;
    int a = 1;

    future<int> ans = async(launch::deferred, &X::exe, &x, ref(a)); // 在当前线程上延后调用任务函数,不会开启其他线程
    do_other_thing();
    ans.wait();

    return 0;
}
future与packaged_task的使用

示例1:

int add(int a, int b)
{
    return a + b;
}

int main()
{
    packaged_task<int(int, int)> task(add);

    future<int> res = task.get_future();
    thread t(move(task), 10, 20);

    cout << res.get() << endl;;
    t.join();
    return 0;
}

示例2:

int bKeepThread;		//是否维持线程
int bPostTaskToThread;	//是否发送任务给线程,并指定任务
mutex mtx;
deque<packaged_task<void()>> tasks_dq;	//任务队列

void Thread()	//用于执行任务的线程
{
    while(bKeepThread) {
        packaged_task<void()> task;
        {
            lock_guard<mutex> lg(mtx);
            if (tasks_dq.empty()) {
                continue;
            }
            task = move(tasks_dq.front());
            tasks_dq.pop_front();
        }
        task();
    }
}

void post_task_to_thread(void f())	//发送任务
{
    packaged_task<void()> task(f);
    lock_guard<mutex> lg(mtx);
    tasks_dq.push_back(move(task));
    cout << tasks_dq.size() << endl;
}

void func_1()
{
    cout << "func_1" << endl;
}

void func_2()
{
    cout << "func_2" << endl;
}

void func_3()
{
    cout << "func_3" << endl;
}

int main()
{
    bKeepThread = 1;		//初始时,先维持线程
    bPostTaskToThread = 1; 	//初始时,先发送func_1给线程
    thread t1(Thread);		//开启线程
    typedef void (*Func)();
    Func arr_f[3] = {&func_1, &func_2, &func_3};

    cout << "Keep Thread and post a task to it?:" << endl;
    while (bKeepThread) {
        if (bPostTaskToThread >= 1 && bPostTaskToThread <= 3) {
            post_task_to_thread(arr_f[bPostTaskToThread - 1]);	//发送任务
        }
        cout << "Keep Thread and post a task to it?:" << endl;
        cin >> bKeepThread >> bPostTaskToThread;
    }
    t1.join();
    cout << "end" << endl;
    return 0;
}

执行:

$ g++ -pthread test.cpp
$./a.out 
Keep Thread and post a task to it?:
1
Keep Thread and post a task to it?:
func_1
1 1
1
Keep Thread and post a task to it?:
func_1
1 2
1
Keep Thread and post a task to it?:
func_2
1 3
1
Keep Thread and post a task to it?:
func_3
0 1
end
future与promise的使用
void setValue(promise<int>& prms)
{
    prms.set_value(123);	//设置future将会获取的值
}

int main()
{
    promise<int> prms;
    future<int> ft = prms.get_future();		//future与promise关联
    thread t(setValue, ref(prms));
    int res = ft.get();
    t.join();
    cout << res << endl;
    return 0;
}
future抛出异常

示例1:异步async

struct Err
{
    char str[10] = "Err";
};

void func()
{
    throw Err();
}

int main()
{
    future<void> ft = async(func);
    try {
        ft.get();
    }
    catch(const Err& err) {
        cout << err.str << endl;
    }
    return 0;
}

示例2:packaged_task

struct Err
{
    char str[10] = "Err";
};

void func()
{
    throw Err();
}

int main()
{
    packaged_task<void()> task(func);
    future<void> ft = task.get_future();
    thread t(move(task));
    t.detach();
    try {
        ft.get();
    }
    catch(const Err& err) {
        cout << err.str << endl;
    }
    return 0;
}

示例3:promise

struct Err
{
    char str[10] = "Err";
};

int main()
{
    promise<void> prms;
    future<void> ft = prms.get_future();
    thread t([&prms](){
        prms.set_exception(make_exception_ptr(Err()));
    });
    t.detach();
    try {
        ft.get();
    }
    catch(const Err& err) {
        cout << err.str << endl;
    }
    return 0;
}
多个线程一起等待

future会独占异步结果,get只能被一个线程调用,因为get会进行移动操作,之后指就不存在了。

shared_future的实例能复制副本,可以持有该类的多个对象,指向同一个异步任务的状态数据。

每个线程复制一个shared_future的副本,为各自线程独自持有,作为各线程内部数据,由标准库正确同步,可以安全访问。

int main()
{
    promise<void> ready_promise, t1_ready_promise, t2_ready_promise;
    shared_future<void> ready_future(ready_promise.get_future());

    chrono::time_point<chrono::high_resolution_clock> start;

    auto fun1 = [&, ready_future]() -> chrono::duration<double, std::milli> 
    {
        t1_ready_promise.set_value();
        ready_future.wait();        // 等待来自 main() 的信号
        return chrono::high_resolution_clock::now() - start;
    };

    auto fun2 = [&, ready_future]() -> chrono::duration<double, std::milli> 
    {
        t2_ready_promise.set_value();
        ready_future.wait();        // 等待来自 main() 的信号
        return chrono::high_resolution_clock::now() - start;
    };

    auto result1 = async(launch::async, fun1);
    auto result2 = async(launch::async, fun2);
 
    // 等待线程变为就绪
    t1_ready_promise.get_future().wait();
    t2_ready_promise.get_future().wait();

    // 线程已就绪,开始时钟
    start = chrono::high_resolution_clock::now();

    // 向线程发信使之运行
    ready_promise.set_value();

    cout << "Thread 1 received the signal "
            << result1.get().count() << " ms after start\n"
            << "Thread 2 received the signal "
            << result2.get().count() << " ms after start\n";
    return 0;
}

限时等待

示例:

condition_variable cv;
mutex cv_m;
atomic<int> i{0};

void waits(int idx)
{
    unique_lock<std::mutex> lk(cv_m);
    auto now = chrono::system_clock::now();
    if(cv.wait_until(lk, now + idx * 100ms, [](){return i == 1;}))
        cerr << "Thread " << idx << " true  i == " << i << '\n';
    else
        cerr << "Thread " << idx << " false i == " << i << '\n';
}

void signals()
{
    this_thread::sleep_for(120ms);
    cerr << "Notifying...\n";
    cv.notify_all();
    std::this_thread::sleep_for(100ms);
    i = 1;
    cerr << "Notifying again...\n";
    cv.notify_all();
}

int main()
{
    std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
    t1.join(); 
    t2.join();
    t3.join();
    t4.join();
}

执行结果:

$ g++ -pthread test.cpp
$ ./a.out 
Thread 1 false i == 0
Notifying...
Thread 2 false i == 0
Notifying again...
Thread 3 true  i == 1

解释:

线程1,2,3分别等待100,200,300ms。在signal线程进入sleep时,线程1等待时间结束,检查i是否为1,结果为false,wait_until返回false;signal线程等待结束后唤醒线程2和3,线程2和3分别检查i是否为1,结果为否,只能释放锁继续进入等待;线程2等待时间结束,检查i是否为1,结果为false,wait_until返回false;signal线程又一次等待结束后,设i为1,唤醒线程3,线程3检查i是否为1,结果为true,wait_until返回true。

这里wait_until包含3个参数,如果时间点未到达就被唤醒,会根据条件是否满足判断向下执行还是继续等待,如果到达了时间点,返回条件结果,直接向下执行

原子定义

atomic<int> counter(0);

void incrementCounter()
{
    for (int i = 0; i < 10000; i++) {
        counter.fetch_add(1, memory_order_relaxed);
    }
}

int main()
{
    thread t1(incrementCounter);
    thread t2(incrementCounter);
    t1.join();
    t2.join();
    cout << "Counter value: " << counter << endl;
    return 0;
}

线程池

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值