【C++后端学习】06、并发编程_线程

一、线程创建

1、 linux api (C语言)

int pthread_create(...);
void pthread_exit(void *retval);
int pthread_join(pthread_t pthread, void **retval);
int pthread_datach(pthread_t thread);
int pthread_cancel(pthread_t pthread);
int pthread_attr_init(pthread_attr_t* attr);

2、C++11标准库

   std::thread ;
	t.joinable();
	t.join();
	t.detach();
	t.get_id();
	this_thread::get_id();
	this_thread::sleep_for(dur);
	this_thread::sleep_util(tp);
	this_thread::yield(); // 放弃线程时间片,系统重新轮询

二、线程并发与死锁

  • 线程默认栈大小: (linux)8MB
  • 并发线程数设置
    • IO密集型,Nthreads = 2Ncpu;
    • 计算密集型,Nthreads = Ncpu+1;
  • 死锁四个必要条件
    • 互斥条件:一个资源每次只能被一个进程使用;
    • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;
    • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺;
    • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系;
  • 死锁线程查找与定位:
    • 1.ps获取id->pstack多次打印堆栈
    • 2.gdb --attach -p pid -> info threads
      ->thread n ->bt
    • 3.top命令查看cpu占用最高的线程,大概判定死锁线程->再查看堆栈

三、线程同步

概念
互斥锁、信号量、条件变量、原子操作、临界区(windows)
1、线程锁

(1) linux api (C语言)
	互斥锁:
	pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态创建
	// 动态创建
	pthread_mutex_t *mutexptr = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
	pthread_mutex_init(mutexptr,NULL);  
	pthread_mutex_lock(mutexptr);
	pthread_mutex_unlock(mutexptr);
	pthread_mutex_destroy(mutexptr);
	读写锁:(只对写操作唯一)
	如果有线程读数据,则允许其它线程执行读操作,但不允许写操作;
	如果有线程写数据,则其它线程都不允许读、写操作;
	pthread_rwlock_t *restrict rwlock;
	pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
	pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
	int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
	int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
	int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
	自旋锁: (线程申请自旋锁时处于一段忙等待时间)
	自旋锁阻塞后不会让出CPU,会一直忙等待,直到得到锁;
	自旋锁在用户态较少用,而在内核态使用的比较多;
	spinlock_t lock;   
	pthread_spin_init(&lock);
	pthread_spin_destroy(&lock);
	pthread_spin_lock(&lock);
	pthread_spin_unlock(&lock);
(2)C++11标准库
 	std::mutex m;
 	m.lock() ;
 	m.unlock() ;
 	m.try_lock();
 	m.try_lock_for(dur);
 	m.try_lock_until(tp);
 	
 	lock_guard<std::mutex> lg(m);
 	unique_lock<std::mutex> ul(m); // 与lock_guard接口相同,另外提供owns_lock()、try_lock()、try_lock_for(dur)、try_lock_until(tp)方法

2、条件变量
条件变量是由互斥量保护的,线程在改变条件变量状态前必须先锁住互斥量。
条件变量与互斥量一起使用的时候,允许线程以无竞争的方式等待特定的条件发生。

(1) linux api (C语言)
    pthread_cond_t  cond;
    pthread_cond_init(&cond, NULL);
    pthread_cond_destroy(&cond);
    pthread_cond_wait(&cond, &lock);
    pthread_cond_broadcast(&cond);
(2)C++11标准库
	std::condition_variable cv;
	cv.notify_one(); // 唤醒一个等待者线程
	cv.notify_all();  // 唤醒所有等待线程
	cv.wait(ul);     // 使用unique_lock来等待通知
	cv.wait_for(ul, dur); // 使用unique_lock来等待通知,等待期限是dur
	cv.wait_until(ul, tp)l; //使用unique_lock来等待通知,直到时间点tp;

3、信号量
信号量对象要放在全局数据区

linux api(C语言)
#include <semaphore.h>
无名信号量:
sem_t *sem;
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t * sem);
int sem_getvalue(sem_t *sem, int *sval);
int sem_wait(sem_t *sem);  // 相对于P操作
int sem_trywait(sem_t *sem); // 非阻塞P
int sem_post(sem_t *sem);  // 相当于V操作

4、原子操作
适用于基本数据类型、pointer类型

C语言:
atomic_<type>, 示例atomic_bool
C++11:
std::atomic<T> a = val;
atomic_init(&a, val);
a.is_lock_free(); // atomic内部是否使用lock
a.store(val);
a.load();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值