适用移动语义可以将一个unique_lock赋值给另一个unique_lock,适用move实现。
void myThread1()
{
unique_lock myUnique (testMutex1,std::defer_lock);
unique_lockmyUnique1(std::move(myUnique));//myUnique 则实效 myUnique1 相当于原来的myUnique
}
std::lock_guard
工程中难免有多个地方要加锁,如果存在交叉调用则会出现异常,递归独占互斥量 std::recursive_mutex 可解决这个问题。
在多线程执行中,如果希望整个生命周期仅调用一次或者变量仅初始化一次,可以适用call_once.
C++11提供了一个函数 std::call_once(标记(once_flag), 函数名);
头文件在#include
#include
#include
#include
#include
using namespace std;
std::once_flag one_flag;
void myThread()//定义线程入口函数
{
cout << "a value " << endl;
}
int main() {
std::call_once(one_flag, myThread);
std::call_once(one_flag, myThread);
return 0;
}
看到这里可能会有些疑惑用互斥锁同样可以实现这个需求,显然互斥锁效率是要低的,因为每次使用这个线程都要上锁然后判断标记位 这样消耗的时间还会更长。
进程具有独立的内存地址空间。多个线程共用同一个地址空间。
从操作系统层级上看,虚拟地址空间主要分为两个部分内核区和用户区。
内核区:
用户区:存储用户程序运行中用到的各种数据。
每个进程的虚拟地址空间都是从 0 地址开始的,我们在程序中打印的变量地址也其在虚拟地址空间中的地址,程序是无法直接访问物理内存的。虚拟地址空间中用户区地址范围是 0~3G,里边分为多个区块:
线程的上下文切换比进程要快的多。切换之前保存当前任务状态。
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
// Compile and link with -pthread, 线程库的名字叫pthread, 全名: libpthread.so libptread.a
参数:
// pthread_create.c
#include
#include
#include
#include
#include
// 子线程的处理代码
void* working(void* arg)
{
printf("我是子线程, 线程ID: %ld\n", pthread_self());
for(int i=0; i<9; ++i)
{
printf("child == i: = %d\n", i);
}
return NULL;
}
int main()
{
// 1. 创建一个子线程
pthread_t tid;
pthread_create(&tid, NULL, working, NULL);
printf("子线程创建成功, 线程ID: %ld\n", tid);
// 2. 子线程不会执行下边的代码, 主线程执行
printf("我是主线程, 线程ID: %ld\n", pthread_self());
for(int i=0; i<3; ++i)
{
printf("i = %d\n", i);
}
// 休息, 休息一会儿...
// sleep(1);
return 0;
}
gcc pthread_create.c -lpthread
动态库名为 libpthread.so 需要使用的参数为 -l,根据规则掐头去尾最终形态应该写成:-lpthread(参数和参数值中间可以有空格)
线程退出函数
#include
void pthread_exit(void *retval);
参数:线程退出的时候携带的数据,当前子线程的主线程会得到该数据。如果不需要使用,指定为 NULL
线程 | 爱编程的大丙
与临界资源相关的上下文代码块成为临界区。
死锁:枷锁后忘记解锁。重复枷锁,造成死锁。
场景描述:
1. 有两个共享资源:X, Y,X对应锁A, Y对应锁B
- 线程A访问资源X, 加锁A
- 线程B访问资源Y, 加锁B
2. 线程A要访问资源Y, 线程B要访问资源X,因为资源X和Y已经被对应的锁锁住了,因此这个两个线程被阻塞
- 线程A被锁B阻塞了, 无法打开A锁
- 线程B被锁A阻塞了, 无法打开B锁
读写锁:读锁是共享的,写锁是独占的。
调用这个函数,如果读写锁是打开的,那么加锁成功;如果读写锁已经锁定了读操作,调用这个函数依然可以加锁成功,因为读锁是共享的;如果读写锁已经锁定了写操作,调用这个函数的线程会被阻塞