基于wordpress的英文小游戏站,浦东做网站,google地图 wordpress,做网站的收入Multithreading 1、线程的基本操作1.1、创建线程1.2、等待线程和分离线程1.3、获取线程id 2、互斥锁3、条件变量4、例程 1、线程的基本操作
从C11开始推出关于多线程的库和函数#xff0c;相比于Linux所配套的资源#xff0c;C11提供的函数更加容易理解和操作#xff0c;对… Multithreading 1、线程的基本操作1.1、创建线程1.2、等待线程和分离线程1.3、获取线程id 2、互斥锁3、条件变量4、例程 1、线程的基本操作
从C11开始推出关于多线程的库和函数相比于Linux所配套的资源C11提供的函数更加容易理解和操作对于跨平台编程更有优势。
1.1、创建线程
导入线程库创建一个新线程让线程执行某个函数。
#include threadusing namespace std; void test_function()
{cout hello, i am a subthread. endl;
}int main()
{thread user_thread(test_function);user_thread.join();return 0;
}可以看出创建一个线程的时候需要一个函数名函数地址作为初始化参数。那么我们使用lambda函数也是可以的。 thread user_thread([]{cout i am a lambda function. endl;});user_thread.join();用类似于函数指针的function也是可以的。 functionvoid() f []{cout function test... endl;};thread user_thread(f);user_thread.join();1.2、等待线程和分离线程
user_thread.join()是为让主线程阻塞等待user_thread这个线程执行完毕。如果使用user_thread.detach()那就是让子线程自己在后台执行。 我在打印function test…之前延时一秒就可以清楚的看出两者的区别了。
int main()
{ functionvoid() f []{this_thread::sleep_for(chrono::seconds(1));cout function test... endl;};thread user_thread(f);user_thread.detach(); //user_thread.join();return 0;
}1.3、获取线程id
每一个线程都有独一无二的id以便于用户辨别。
std::this_thread::get_id();2、互斥锁
互斥锁mutexMutual Exclusion Object是用于确保数据一致性和解决资源竞争的一种方法。被互斥锁锁住的资源其它线程将无法访问。值得注意的是这里锁住的并不是代码块而是资源即变量数组之类的东西。 上锁和解锁是配套的操作否则将导致某一资源永远无法被访问。
#include iostream
#include thread
#include mutexusing namespace std; int temp 0;
mutex mu;void thread_1()
{mu.lock();temp;cout this_thread::get_id() temp endl;mu.unlock();
}void thread_2()
{mu.lock();temp;cout this_thread::get_id() temp endl;mu.unlock();
}int main()
{ thread thread1(thread_1);thread thread2(thread_2);thread1.join();thread2.join();system(pause);return 0;
}其实像这样裸照上锁解锁还是比较少见的更多的是利用uniuqe_locker这个类来上锁。因为使用这个类提供了需要方法在离开作用域的时候还会自动解锁并且支持和条件变量配套使。
void thread_1()
{unique_lockmutex locker(mu);temp;cout this_thread::get_id() temp endl;//不必再解锁了。
}unique_lock这个类在构造函数中执行上锁操作在析构函数中执行解锁操作。但它也支持手动上锁和解锁。上锁的方式也有好几种我们不妨都看一下。 首先要求实例化的时候不要自动上锁。
unique_lockmutex locker(mu, std::defer_lock);locker.lock()默认模式阻塞式上锁。locker.try_lock()尝试获取资源状态如果被已经被锁住则返回true反之返回false。如果不加判断的使用该方法则可能导致上锁失败。locker.try_lock_for()输入参数是滞留时间指定时间该资源还是无法访问则返回false。locker.try_lock_until()输入参数是目标时间目标时间内还是无法访问该资源则返回false。
给个例子简单看看怎么用吧。
void thread_1()
{unique_lockmutex locker(mu, defer_lock);//等待一秒钟如果还无法访问资源则离开if(locker.try_lock_for(chrono::seconds(1))){temp;cout this_thread::get_id() temp endl;}
}3、条件变量
条件变量conditional variable主要用于协调多线程经常和互斥锁一起使用。其设有通知机制分为单个通notify_one知和全部通知notify_all两种模式前者通知任意一个线程后者通知所有线程。
#include mutex
#include condition_variable
//定义一个条件变量
condition_variable cond;
//定义一个互斥锁
mutex mtu;定义好条件变量和互斥锁之后线程就等待该条件变量被唤醒即可。
void thread_test()
{unique_lockmutex locker(mtu);cond.wait(locker);
}int main()
{thread myThread(thread_test);//延迟一下以便测试条件变量的作用this_thread::sleep_for(chrono::seconds(2));//notify_one是通知任意一个线程notify_all是通知所有线程cond.notify_one();myThread.join();return 0;
}如果缺乏互斥锁那就有可能出现竞争等情况。比如该条件变量其实只唤醒了一次但两个线程却争着被唤醒以至于两个线程同时被唤醒。 条件变量等待通知唤醒的方式也有三种类比互斥锁的那几种锁方式便知道如何使用了。这里不再赘述。
wait()阻塞式等待。wait_for()输入参数中有一个滞留时间滞留时间到达之后即便还没有接到通知也会继续执行下去。wait_until()输入参数中有一个目标时间同理目标时间到达之后即便还没有接到通知也会继续执行下去。
这里有个点需要知道如果再通知的那一刻所有线程都处于忙碌状态那么该通知就会被忽略。
void thread_test_2()
{unique_lockmutex locker(mtu);if(cond.wait_for(locker, chrono::seconds(1)) cv_status::timeout)cout time out endl; //会在1s之后执行这个打印语句elsecout i am thread test 2 ! endl;
}
int main()
{thread myThread2(thread_test_2);this_thread::sleep_for(chrono::seconds(5));cond.notify_all();myThread2.join();system(pause);return 0;
}如果不仅仅想要判断条件变量还想同时判断其它条件可以这样做。
bool isReady false;
unique_lockmutex locker(mtu);
cond.wait(locker, isReady);当然传入lambda函数或其它返回值为bool类型的函数也是可以的。
cond.wait(locker, []{cout this is lambda function endl;return isReady;});不过有几点比较奇怪的是你不能在执行cond.wait()语句之前就让函数的返回值是true否则它会直接终止等待执行下面的语句。 即你不能这样。
cond.wait(locker, true});至于wait_for和wait_until如何仿造上面同时进行多个判断我也没学明白。。需要时候再学吧。
4、例程
自己写了一个线程池可能不严谨。 大致思路如下 1、定义一个任务队列里面存放N个任务。 2、定义M个线程存放在vector容器中。让这些线程不断往任务队列中取出任务并执行之。 3、每添加一个任务进任务队列就会唤醒任意一个空闲线程去读取任务。 4、用互斥锁去保证任务队列读写任务的顺利执行并保证条件变量的效果。 5、在析构函数中即整个程序结束前不断唤醒空闲线程去取任务直至任务队列为空。
#include iostream
#include mutex
#include thread
#include queue
#include vector
#include functional
#include condition_variableusing namespace std;class ThreadPool
{
public:ThreadPool(int size) : _size(size), _isStop(false){//emplace some thread into thread_vectorfor(int i 0; i _size; i) thread_vector.emplace_back(//using lambda function to execute task[this]{functionvoid() thraed_task;//all of threads will keep working until receive stop signal.while(true){unique_lockmutex locker(mtu);//waiting until queue is not emptycond.wait(locker, [this]{return _isStop || !task_queue.empty();});if(_isStop task_queue.empty()) break;thraed_task task_queue.front();task_queue.pop();mtu.unlock();thraed_task();} });}~ThreadPool(){while(!task_queue.empty())cond.notify_all();_isStop true;for(int i 0; i _size; i) thread_vector[i].join();cout deconstructor endl;}void enqueue_task(functionvoid() task){//we neednt consider mutex in different resource.unique_lockmutex locker(mtu);task_queue.push(move(task));cond.notify_one();mtu.unlock();}private:int _size;bool _isStop;mutex mtu;condition_variable cond;queuefunctionvoid() task_queue;vectorthread thread_vector;
};void HandleTask(int cnt)
{printf(thread %d handle the %d task!\n, this_thread::get_id(), cnt);this_thread::sleep_for(chrono::seconds(1)); // Simulate work
}int main()
{//limit scope{ThreadPool pool(3);for (int i 0; i 9; i) {pool.enqueue_task([i] { HandleTask(i 1); });}}system(pause);return 0;
}