c++多线程基础一

1、线程的启动结束和创建线程

1.1 thread 创建

c++ 11之前的linux创建方法:
pthread_create 创建线程, pthread_create使用

三种创建方法:

  1. 用一个初始函数创建一个线程

    #include <iostream>
    #include <thread>
    
    using namespace std;
    
    void print1()
    {
    	cout << "print1_1线程执行" << endl;
    	cout << "print1_2线程执行" << endl;
    	cout << "print1_3线程执行" << endl;
    }
    
    int main()
    {
    	thread mythread1(print1);
    	mythread1.join();
    	cout << "主线程执行" << endl;
    	return 0;
    }
    
  2. 用类对象创建一个线程

    #include <iostream>
    #include <thread>
    
    using namespace std;
    
    class T
    {
    public:
    	void operator()()
    	{
    		cout << "print2_1线程执行" << endl;
    		cout << "print2_2线程执行" << endl;
    		cout << "print2_3线程执行" << endl;
    	}
    };
    
    int main()
    {
    	T t;
    	thread mythread2(t);
    	mythread2.join();
    	cout << "主线程执行" << endl;
    	return 0;
    }
    
  3. 用lambda表达式创建一个线程

    #include <iostream>
    #include<thread>
    using namespace std;
    int main()
    {
        //用lambda表达式创建一个线程
        auto mylamthread = [] {//这是一个lambda表达式
            cout << "我的线程开始执行了" << endl;
            //......
            cout << "我的线程执行结束了" << endl;
        };
        thread mythread3(mylamthread);
        mythread3.join();
        cout << "主线程执行结束" << endl;
        return 0;//表示主线程执行结束,表明进程结束
    }
    

同时,使用thread变量,再连接线程执行函数:

std::thread t;
t = std::thread(fun);

1.2 join方法

join()函数是一个等待线程完成函数,主线程需要等待子线程运行结束了才可以结束
注意:这里相当于主线程在这里等待子线程结束运行,才执行之后的命令

1.3 detach方法

detach()函数是子线程的分离函数,当调用该函数后,线程就被分离到后台运行,主线程不需要等待该线程结束才结束;称为守护线程或者分析线程。

linux 启动程序变为后台进程,可以使用在最后加入&即可;
注意:detach 线程后注意子线程和主线程中变量的关系,防止引用或者指针主线程释放的场景,导致子线程异常。

  • 传递临时对象作为线程参数
  • 传递临时变量作为线程参数
  • 传递类对象或者只能指针作为宪政参数
  • 使用成员函数指针作为线程参数

1.4 joinable方法

用于判断程序是否可以使用detach或者join方法,同时也是为了防止多次调用join导致异常,如果已经join,则返回false

1.5 获取线程ID

  1. 调用pthread_create 返回值即为线程id

    #include <pthread.h>
    
    pthread_t tid;
    tid = pthread_create(&tid, NULL, thread_proc, NULL);
    
  2. pthread_self 函数获取

    #include <pthread.h>
    
    pthread_t tid = pthread_self();
    tid = pthread_create(&tid, NULL, thread_proc, NULL);
    
  3. syscall调用系统获取

    #include <sys/syscall.h>
    #include <unistd.h>
    
    int tid = syscall(SYS_gettid);
    
  4. get_id 调用

    #include <thread>
    
    std::thread::id id = std::this_thread::get_id();
    

2 如何确保创建的线程一定能够运行

使用条件变量通知:

#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>

std::mutex mymutex;
std::condition_variable mycv;
bool success = false;

void thread_func()
{
    {
        std::unique_lock<std::mutex> lock(mymutex);
        success = true;
        mycv.notify_all();
    }

    while(true) {

    }
}

int main()
{
    std::thread t(thread_func);

    // 使用{} 减小锁的粒度
    {
        std::unique_lock<std::mutex> lock(mymutex);
        while(!success) {
            mycv.wait(lock);
        }
    }

    std::cout<< "start thread successfully." << std::endl;

    t.join();
    return 0;
}

3 线程局部变量

3.1 linux 线程局部变量

linux 上的NTPL 提供了一套函数接口来实现线程局部存储功能:

int pthread_key_create(pthread_key_t* key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t* key);

int pthread_setspecific(pthread_key_t* key, const void* value);
void* pthread_getspecific(pthread_key_t* key);

示例:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

pthread_key_t thread_log_key;

void write_to_thread_log(const char* message)
{
    if (message == NULL) {
        return;
    }

    FILE* logfile = (FILE*) pthread_getspecific(thread_log_key);
    fprintf(logfile, "%s\n", message);
    fflush(logfile);
}

void close_thread_log(void* logfile)
{
    char logfilename[128];
    sprintf(logfilename, "close logfile: thread%ld.log\n", (unsigned long)pthread_self());

    printf("%s\n", logfilename);
    fclose((FILE*)logfile);
}

void* thread_function(void* args)
{
    char logfilename[128];
    sprintf(logfilename, "thread%ld.log", (unsigned long)pthread_self());

    FILE* logfile = fopen(logfilename, "w");
    if (logfile != NULL) {
        pthread_setspecific(thread_log_key, logfile);
        write_to_thread_log("Thread starting ...");
    }

    return NULL;
}

int main()
{
    pthread_t threadIDs[5];
    pthread_key_create(&thread_log_key, close_thread_log);
    for(int i = 0; i < 5; i++) {
        pthread_create(&threadIDs[i], NULL, thread_function, NULL);
    }

    for(int i = 0; i < 5; i++) {
        pthread_join(threadIDs[i], NULL);
    }

    return 0;
}

编译:

gcc -g -o linux_local_thread linux_local_thread.cpp -lpthread

运行:

lhh@DESKTOP-KDO04Q4:/mnt/d/project_code/c++Server$ ./linux_local_thread
close logfile: thread140045352830720.log

close logfile: thread140045361284864.log

close logfile: thread140045369739008.log

close logfile: thread140045344376576.log

close logfile: thread140045378193152.log

4 线程池实例

4.1 类设计

thread_pool.h
class ThreadPool
{
public:
    ThreadPool(int thread_count):
        thread_count_(thread_count)
    {
    }
    ~ThreadPool();

    bool Init();
    void Submit(std::function<void ()> task);
    void Shutdown();

private:
    void ThreadWorker();
    void Wait();

    int thread_count_;
    std::mutex mutex_;
    std::mutex cv_mutex_;
    std::condition_variable cv_;
    bool shutdown_ = false;
    std::queue<std::function<void ()>> pending_tasks_;
    std::vector<std::thread> threads_;
    
};

4.2 thread_pool实现细节

thread_pool.c
ThreadPool::~ThreadPool()
{
}

bool ThreadPool::Init()
{
    for (int i = 0; i < thread_count_; ++i) {
        threads_.push_back(std::move(std::thread(std::bind(&ThreadPool::ThreadWorker, this))));
    }
    return true;
}

void ThreadPool::ThreadWorker()
{
    while (!shutdown_) {
        while (!pending_tasks_.empty()) {
            std::function<void ()> task;
            {
                std::lock_guard<std::mutex> lock(mutex_);
                if (!pending_tasks_.empty()) {
                    task = pending_tasks_.front();
                    pending_tasks_.pop();
                }
            }
            if (task) {
                task();
            }
        }
        Wait();
    }
}

void ThreadPool::Submit(std::function<void ()> task)
{
    {
        std::lock_guard<std::mutex> lock(mutex_);
        pending_tasks_.push(task);
    }
    cv_.notify_all();
}

void ThreadPool::Wait()
{
    std::unique_lock<std::mutex> lk(cv_mutex_);
    cv_.wait_until(lk, std::chrono::steady_clock::now() + std::chrono::seconds(1));
}

void ThreadPool::Shutdown()
{
    shutdown_ = true;
    for (auto& thread: threads_) {
        thread.join();
    }
}
posted @ 2021-01-13 15:55  lihaihui199102  阅读(131)  评论(0)    收藏  举报