一、线程相关操作

1、线程的创建

线程体函数种类:
1、可以是任意类型的函数,不必要是 void * 类型参数也是void *类型
2、可以是全局函数,也可以是类中成员函数当做线程体
3、可以是仿函数当作线程体函数
4、也可以是Lambda表达式当作线程体函数
#include<myhead.h>
#include <thread> //要包含线程头文件

void func1(){
    //输出当前线程的线程号
    cout<<"func1的调用,id="<<this_thread::get_id()<<endl;
}

void func2(int num,string s){
    cout<<"func2的调用"<<endl;
    cout<<"num="<<num<<"  s="<<s<<endl;
}

class ThreadTest{
private:
    int num;
    string name;
public:
    void setNum(int num){
        this->num=num;
    }
    void setName(string name){
        this->name=name;
    }
    void func(){  //类中成员函数作为线程体函数
        cout<<"thread 3 的调用"<<endl;
        cout<<"num="<<num<<" name="<<name<<endl;
    }
};
 
int main(int argc, const char *argv[]){

    //1、创建第1个线程并执行线程体,线程体是无参函数
    thread t1(func1);

    //2、创建第2个线程并执行线程体,线程体是有参函数
    thread t2(func2,1314,"name");

    //3、创建第3个线程并执行线程体,线程体是类中成员函数
    ThreadTest test;
    test.setNum(520);
    test.setName("zhangsan");
    thread t3(&ThreadTest::func,&test);

    //4、创建第4个线程并执行线程体,线程体是lambda表达式
    int key=1024;
    thread t4([](int key){
        cout<<"thread 4 的调用"<<endl;
        cout<<"key="<<key<<endl;       
    },key);

    //阻塞回收分支线程
    t1.join();
    t2.join();
    t3.join();
    t4.join();

    cout<<"hello thread"<<endl;
    
    return 0;
}

运行结果:

注意:各个线程运行的先后顺序随机,此处仅展示其中一种运行结果

2、线程号的获取

该函数会返回一个很大的整数

this_thread::get_id()

3、线程的回收

1、阻塞方式回收线程:th1.join();
2、非阻塞形式回收线程:th.detach();
#include<myhead.h>

void func(){
    for(int i=0;i<10;i++){
        cout<<"hello thread"<<endl;
        this_thread::sleep_for(std::chrono::seconds(1)); //等待1s的时间
    }
}
 
int main(int argc, const char *argv[]){
    thread t1(func);
    // 阻塞回收分支线程
    //th1.join();

    t1.detach();  //将线程设置成分离态,主线程可以干自己其他事情
    cout<<"exit"<<endl;
    this_thread::sleep_for(std::chrono::seconds(5)); //等待1s的时间
    return 0;
}

二、互斥锁

互斥锁本质上是完成将多个线程使用临界资源时,防止竞态。

常用函数:

1、构造函数:创建一个互斥锁对象
2lock():上锁
3unlock()释放锁资源
#include<myhead.h>
#include<mutex>  //引入互斥锁头文件
mutex mux;

void task(){
    mux.lock();
    cout<<"---------------"<<endl;
    cout<<"tid = "<<this_thread::get_id()<<endl;
    cout<<"***************"<<endl;
    mux.unlock();
}
 
int main(int argc, const char *argv[]){
    for(int i=0;i<10;i++){
        thread t(task);
        t.detach();
    }
    this_thread::sleep_for(std::chrono::seconds(5));
    return 0;
}

三、条件变量

实现一个生产者对应多个消费者问题

常用函数

1、构造函数:创建并初始化一个条件变量

2、wait():将消费者线程放入等待队列中

3、唤醒线程:
        cond.notify_one(); 唤醒一个线程
        cond.notify_all(); 唤醒所有线程
#include<myhead.h>
#include<mutex>
#include<condition_variable> //引入条件变量头文件

condition_variable cond;
mutex mux;

void producerProcess(){ //生产者
    while(1){
        this_thread::sleep_for(std::chrono::seconds(1));
        cout<<"生产了一件物品"<<endl;

        //通知一个线程可以消费了
        cond.notify_one();

        //通知所有消费者线程
        //cv.notify_all();
    }
}

void consumerProcess(){ //消费者
    while(1){
        unique_lock<mutex> lock(mux); //自动上锁
        cond.wait(lock);

        cout<<"消费了一件物品"<<endl;

        lock.unlock(); //解锁
    }    
}
 
int main(int argc, const char *argv[]){
    thread p1(producerProcess);
    thread c1(consumerProcess);
    thread c2(consumerProcess);

    p1.join();
    c1.join();
    c2.join();
    return 0;
}

四、实例

1、多线程实现linux的 cp 指令,一个线程拷贝文件前一半,另一个拷贝后一半。

#include <myhead.h>

/*
    src:源文件描述符
    dest:拷贝后的文件描述符
    start:拷贝开始的起点
    size:本次拷贝的字节数
*/
void task(int src,int dest,int start,int size){
    lseek(src,start,SEEK_SET);
    lseek(dest,start,SEEK_SET);
    int sum=0;
    char buf[128];
    while(1){
        int pos=read(src,buf,sizeof(buf));
        sum+=pos;
        if(sum>=size){
            write(dest,buf,pos-(sum-size));
            break;
        }
        write(dest,buf,pos);
    }
}
 
int main(int argc, const char *argv[]){
    if(argc!=3){
        printf("copy error\n");
        printf("usage: ./copy srcfile destfile\n");
        return -1;
    }
    int srcfd=-1,destfd=-1;
    if((srcfd=open(argv[1],O_RDONLY))==-1){
        perror("src file open error");
        return -1;
    }
    if((destfd=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC,0664))==-1){
        perror("dest file open error");
        return -1;
    }
    long size=lseek(srcfd,0,SEEK_END);  //获取文件大小,单位:字节
    thread t1(task,srcfd,destfd,0,size/2);
    thread t2(task,srcfd,destfd,size/2,size-size/2);

    t1.join();
    t2.join();
    return 0;
}
2、使用条件变量完成线程同步,定义三个线程,线程1打印A,线程2打印B,线程3打印C,最终输出的结果为ABCABCABCABC...
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;

mutex mux;
condition_variable cond;
int current=-1; //current为 0表示打印A,1表示打印B,2表示打印C 

void printA(){
    while(1){
        unique_lock<mutex> lock(mux);
        cond.wait(lock,[]{return current==0;});
        this_thread::sleep_for(chrono::seconds(1)); //睡眠1s
        cout<<"A";
        cout.flush();  //手动刷新缓冲区,不然会等到缓冲区满才会输出到屏幕
        current=1;
        cond.notify_all();
    }
}

void printB(){
    while(1){
        unique_lock<mutex> lock(mux);
        cond.wait(lock,[]{return current==1;});
        this_thread::sleep_for(chrono::seconds(1)); //睡眠1s
        cout<<"B";
        cout.flush();
        current=2;
        cond.notify_all();
    }
}

void printC(){
    while(1){
        unique_lock<mutex> lock(mux);
        cond.wait(lock,[]{return current==2;});
        this_thread::sleep_for(chrono::seconds(1)); //睡眠1s
        cout<<"C";
        cout.flush();
        current=0;
        cond.notify_all();
    }
}
 
int main(int argc, const char *argv[]){
    thread a(printA);
    thread b(printB);
    thread c(printC);

    ​// 此处​{ }的作用​​:创建一个独立作用域
    // 限定 std::lock_guard的生命周期,
    // 确保锁在 notify_all()之后立即释放。
    { 
        unique_lock<mutex> lock(mux);
        current=0;
        cond.notify_all();
    }

    a.join();
    b.join();
    c.join();

    return 0;
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐