临界资源:
对于同一进程的多个线程,进程资源中有些对线程是共享的,但有些资源一次只能供一个线程使用,这样的资源被称为临界资源,也可以叫做互斥资源,即只能被各个线程互斥访问。
临界区:
线程中对临界资源实施操作的那段程序,称之为临界区。
线程间的同步互斥:
同步和互斥。同步是合作进程(或线程)间的直接制约问题,互斥是申请临界资源进程(或线程)间的直接制约问题。
1.1.线程间的同步
线程的同步是指在一些确定点上需要线程之间相互合作,协同工作。个人认为,说白了就是在访问同一个临界资源(互斥资源)时,两个线程间必须有一个先后顺序,因为临界资源一次只能供一个线程使用,如果两个线程都想要访问,那岂不乱套了,这回形成死锁,后面会讲。
举例:假如程序中有一个静态变量,static int a;线程1负责往里写入数据,线程2需要读取其中的数据,那么线程2在读数据之前必须是线程1写入了数据,如果不是,那么线程2必须停下来等待线程1的操作结束。这就是线程之间在某些地方上的合作关系,协同工作嘛!
1.2.线程间的互斥
线程的互斥是指同一进程中的多个线程之间因争用临界资源而互斥的执行,即一次只能有一个线程访问临界资源。
举例:还是假如程序中有一个静态变量,static int b;线程1想要往里写入数据,线程2也想要往里写入数据,那么此时静态变量b就是一个临界资源(互斥资源),即一次只能被一个线程访问。想一想,如果线程1和线程2同时往b中写入数据,那怎么能行,计算机是不允许的!所以,要么是线程1占用b,此时线程2要等待;要么是线程2占用b,此时线程1等待。这就是所谓的线程间的互斥,这里可以通过加锁的方式来实现。
创建线程:
thread first(线程函数名,参数1,参数2,…);每个线程有一个线程函数,线程要做的事情就写在线程函数中。
主线程和子线程之间是同步的关系,即主线程要等待子线程执行完毕才会继续向下执行,join()是一个阻塞函数。
而first.detach(),当然上面示例中并没有应用到,则表示主线程不用等待子线程执行完毕,两者脱离关系,完全放飞自我。这个一般用在守护线程上:有时候我们需要建立一个暗中观察的线程,默默查询程序的某种状态,这种的称为守护线程。这种线程会在主线程销毁之后自动销毁。
C++中一个标准线程函数只能返回void,因此需要从线程中返回值往往采用传递引用的方法。我们讲,传递引用相当于扩充了变量的作用域。
互斥锁
互斥锁用于控制多个线程对他们之间共享资源互斥访问的一个信号量。也就是说是为了避免多个线程在某一时刻同时操作一个共享资源。例如线程池中的有多个空闲线程和一个任务队列。任何是一个线程都要使用互斥锁互斥访问任务队列,以避免多个线程同时访问任务队列以发生错乱。
在某一时刻,只有一个线程可以获取互斥锁,在释放互斥锁之前其他线程都不能获取该互斥锁。如果其他线程想要获取这个互斥锁,那么这个线程只能以阻塞方式进行等待。
头文件:<pthread.h>
类型:pthread_mutex_t,
函数:pthread_mutex_init(pthread_mutex_t * mutex, const phtread_mutexattr_t * mutexattr);//动态方式创建锁,相当于new动态创建一个对象
pthread_mutex_destory(pthread_mutex_t *mutex)//释放互斥锁,相当于delete
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//以静态方式创建锁
pthread_mutex_lock(pthread_mutex_t *mutex)//以阻塞方式运行的。如果之前mutex被加锁了,那么程序会阻塞在这里。
pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t * mutex);//会尝试对mutex加锁。如果mutex之前已经被锁定,返回非0,;如果mutex没有被锁定,则函数返回并锁定mutex
//该函数是以非阻塞方式运行了。也就是说如果mutex之前已经被锁定,函数会返回非0,程序继续往下执行。
unique_ptr智能指针
使用 std::make_unique函数 创建 unique_ptr 对象 / C++14
std::unique_ptr<Task> taskPtr = std::make_unique<Task>(34);
make_unique会申请34个Task类型的内存并把它的原始指针给unique_ptr.