c++多线程

多线程并发指的是在同一个进程中执行多个线程,线程是轻量级的进程,同一进程中的多个线程共享相同的地址空间,可以访问进程中的大部分数据,指针和引用可以在线程间进行传递。

简单创建使用

头文件:

#include <thread>

创建线程:

第一种
std::thread myThread (thread_fun);  //创建线程myThread,线程中传入函数thread_fun
myThread.join();
---------------------------
第二种
std::thread myThread (thread_fun(100));
myThread.join();
---------------------------
第三种
std::thread (thread_fun,1).join();
  • detach方式,启动的线程自主在后台运行,当前的代码继续往下执行,不等待新线程结束。
  • join方式,等待启动的线程完成,才会继续执 执行下面的代码。

代码例:

#include <iostream>
#include <thread>

using namespace std;

void thread_1()
{

  cout << "子线程1" << endl<<endl;
}
void thread_2(int x)
{
  cout << "子线程2,x="<<x << endl<< endl;
}

void thread_3(int x)
{
  cout << "子线程3,x=" <<x<< endl<< endl;
}

int main()
{
  cout<<"--------------------------------------------"<<endl;
  thread first(thread_1);       // 开启线程,调用:thread_1()
  thread second(thread_2, 2); // 开启线程,调用:thread_2(100)
  thread third(thread_3, 3);    // 开启第3个线程,共享thread_2函数。

   first.join(); // 必须说明添加线程的方式
   second.join();
   third.join();

  std::cout <<"+++++++++++\n这是主线程+\n+++++++++++\n\n";
  
  std::cout << "子线程结束.\n"; // 必须join完成

  cout<<"---------------------------------------------"<<endl;
  return 0;
}

编译:g++ test.cc -o test -l pthread

运行:./test

结果:

可以发现执行多次,每次执行可能不相同,因为线程是并发进行的。

同时可以发现“这是主线程”永远在三个线程执行结果后面,因为线程的执行方式是join,必须要等线程执行完了之后才可以执行接下来的代码(非声明join或detach的代码)。

 注:

可以使用joinable判断是join模式还是detach模式。

if (myThread.joinable()) foo.join()

 this_thread

std::this_thread::get_id()    获取线程id
std::this_thread::yield()    放弃线程执行,回到就绪状态
std::this_thread::sleep_for(std::chrono::seconds(1));    暂停1秒(sleep_until也可以达到类似的效果)

死锁

mutex

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex

using namespace std;
mutex mtx1;          
mutex mtx2;
void print_block1 (int n, char c) {

  mtx1.lock();
  for (int i=0; i<n; ++i) { cout << c; }
  cout << '\n';
  mtx1.unlock();
}
void print_block2 (int n, char c) {

  mtx1.lock();
  for (int i=0; i<n; ++i) { cout << c; }
  cout << '\n';
  mtx1.unlock();
}
int main ()
{
    thread th1 (print_block1,300,'*');//线程1:打印*
    thread th2 (print_block2,300,'$');//线程2:打印$
  th1.join();
  th2.join();

  return 0;
}

 因为两个打印程序使用的是同一个mutex,所以互斥,不会同时执行。如果把第二个函数的mutex变量换成mtx2就会出现下面交替打印的情况:

lock_gaurd

作用:为了防止在线程使用mutex加锁后异常退出导致死锁的问题,建议使用lock_guard代替mutex。

(1) 创建即加锁,作用域结束自动析构并解锁,无需手工解锁
(2) 不能中途解锁,必须等作用域结束才解锁
(3) 不能复制

格式:template<class Mutex> class lock_guard;

eg:lock_gurad<std::mutex> lock(mtx)

unique_lock

unique_lock不仅可以使用在简单的临界代码段的互斥操作中,还可以使用在函数调用过程中

std::unique_lock<std::mutex>  munique(mlock,参数);

参数可以是:

std::try_to_lock:会判断当前mutex能否被lock,如果不能被lock,可以先去执行其他代码

std::unique_lock<std::mutex> munique(mlock, std::try_to_lock);
		if (munique.owns_lock() == true) {
			s += i;
		}
		else {
			// 执行一些没有共享内存的代码
		}
	}

std::defer_lock: 这个参数表示暂时先不lock,之后手动去lock,但是使用之前也是不允许去lock。一般用来搭配unique_lock的成员函数去使用。

std::unique_lock<std::mutex> munique(mlock, std::defer_lock);
munique.lock();
s += i;
munique.unlock();       

还有一个成员函数是try_lock,和上面的try_to_lock参数的作用差不多,判断当前是否能lock,如果不能,先去执行其他的代码并返回false,如果可以,进行加锁并返回true

release函数,解除unique_lock和mutex对象的联系,并将原mutex对象的指针返回出来。

std::unique_lock<std::mutex> munique(mlock);   // 这里是自动lock
std::mutex *m = munique.release();
s += i;
m->unlock();

参考:C++多线程unique_lock详解 - 腾讯云开发者社区-腾讯云

简单的场景,不涉及线程通信时,可以使用 lock_guard, 但是涉及函数调用或线程通信时 使用 unique_lock

参考:

一文详解C++多线程_非晚非晚的博客-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值