C++多线程入门笔记

参考:
https://blog.csdn.net/qq_44891434/article/details/132559929
https://www.cnblogs.com/chen-cs/p/13055211.html

#include 
std::thread t(function_name, args...);

function_name是线程入口点的函数或可调用对象
args…是传递给函数的参数,当调用的函数是无参的可以空着。
创建线程后,我们可以使用t.join()等待线程完成,join()函数的作用是让主线程的等待该子线程完成,然后主线程再继续执行
或者使用t.detach()分离线程,让它在后台运行。
一个子线程只能调用join()和detach()中的一个,且只允许调用一次。
使用**++ -std=c++11 -o thread thread.cpp -lpthread**编译

等待线程完成.join()

#include 
#include 
void print_message(const std::string& message) {
	std::cout << message << std::endl;
}
void increment(int& x) {    
    ++x;
}
int main() {    
    std::string message = "Hello, world!";    
    std::thread t(print_message, message);    
    t.join();    
    int x = 0;    
    std::thread t2(increment, std::ref(x));    
    t2.join();    
    std::cout << x << std::endl;    
    return 0;
}

输出:

Hello, world!
1

分离线程.detach()

有时候我们可能不需要等待线程完成,而是希望它在后台运行。这时候我们可以使用t.detach()方法来分离线程。

#include 
#include 
void print_message(const std::string& message) {    
    std::cout << message << std::endl;
}
int main() {    
    std::thread t(print_message, "Thread 1");    
    t.detach();    
    std::cout << "Thread detached" << std::endl;    
    return 0;
}

Thread detached
Thread 1

可以是主进程完成之后在进行子进程

线程是否被调用.joinable()

因为join和detach智能调用一次,所以可以使用joinable来判断是否可以使用该线程
针对一个线程,可以调用detach,或者join。两者是互斥的关系,也就说一旦调用了join,detach就不能再调用了,反之亦成立。判断是否已经使用过join或者detach可以用joinable。

	std::thread t(print_message, "Thread 1");    
    std::cout << t.joinable() << std::endl; 
    t.join();    
    std::cout << "Thread detached" << std::endl;  
    std::cout << t.joinable() << std::endl;  

1
Thread 1
Thread detached
0

往线程里穿临时变量要用参考的方式引用

	int i=1;
    std::thread t(foo, std::ref(i)) #std::thread t(foo, 1);

如果是直接浅拷贝传递临时变量给线程,那么线程在执行的时候,临时变量会被销毁

互斥量mutex

当不同的线程同事访问改写一个数据的时候,就可能出现数据竞争的关系,为避免数据竞争问题,可以使用同步机制()包括互斥量、条件变量、原子操作)来保证访问安全。

void func(int n) {
    for (int i = 0; i < 10; ++i) {
        //mtx.lock();
        shared_data++;        
        std::cout << "Thread " << n 
        << " increment shared_data to " << shared_data << std::endl;
        //mtx.unlock();
    }
}
int main() {
    std::thread t1(func, 1);
    std::thread t2(func, 2);

在不设置互斥锁的情况下,访问和修改是无序的

Thread 2 increment shared_data to 2
Thread 2 increment shared_data to 3
Thread 2 increment shared_data to 4
Thread 2 increment shared_data to 5
Thread 2 increment shared_data to 6
Thread 2 increment shared_data to 7
Thread 2 increment shared_data to 8
Thread 2 increment shared_data to 9
Thread 2 increment shared_data to 10
Thread 2 increment shared_data to 11
Thread 1 increment shared_data to 11
Thread 1 increment shared_data to 12
Thread 1 increment shared_data to 13
Thread 1 increment shared_data to 14
Thread 1 increment shared_data to 15
Thread 1 increment shared_data to 16
Thread 1 increment shared_data to 17
Thread 1 increment shared_data to 18
Thread 1 increment shared_data to 19
Thread 1 increment shared_data to 20

先调用 mtx.lock() 来获取互斥量的所有权,然后对 shared_data 变量进行累加操作,最后再调用 mtx.unlock() 来释放互斥量的所有权。

互斥量死锁

假设有两个线程 T1 和 T2,它们需要对两个互斥量 mtx1 和 mtx2 进行访问,而且需要按照以下顺序获取互斥量的所有权:

T1 先获取 mtx1 的所有权,再获取 mtx2 的所有权。
T2 先获取 mtx2 的所有权,再获取 mtx1 的所有权。

当两个都在等对方释放资源的时候就可能会造成死锁

void func1() {    
    mtx2.lock();    
    std::cout << "Thread 1 locked mutex 2" << std::endl;    
    mtx1.lock();    
    std::cout << "Thread 1 locked mutex 1" << std::endl;    
    mtx1.unlock();    
    std::cout << "Thread 1 unlocked mutex 1" << std::endl;    
    mtx2.unlock();    
    std::cout << "Thread 1 unlocked mutex 2" << std::endl;
}
void func2() {    
    mtx2.lock();    
    std::cout << "Thread 2 locked mutex 2" << std::endl;    
    mtx1.lock();    
    std::cout << "Thread 2 locked mutex 1" << std::endl;    
    mtx1.unlock();    
    std::cout << "Thread 2 unlocked mutex 1" << std::endl;    
    mtx2.unlock();    
    std::cout << "Thread 2 unlocked mutex 2" << std::endl;
}

在上述实例中,两者都先强调mtx2,再强调mtx1,所以谁先抢到mtx2谁先执行,还有个函数try_lock()其功能和joinable差不多。

Thread 1 locked mutex 2
Thread 1 locked mutex 1
Thread 1 unlocked mutex 1
Thread 1 unlocked mutex 2
Thread 2 locked mutex 2
Thread 2 locked mutex 1
Thread 2 unlocked mutex 1
Thread 2 unlocked mutex 2

原子操作

指事务的不可分割性,一个事务的所有操作要么不间断地全部被执行,要么一个也没有执行。
其定义方式atomic x,在对它进行操作是原子性的,不会出现数据竞争问题

#include 
#include 
#include 
std::atomic<int> count = 0;
void increment() {
    for (int i = 0; i < 1000000; ++i) {
        count++;
    }
}
int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << count << std::endl;
    return 0;
}

你可能感兴趣的:(c++,开发语言)