Linux--线程的控制

时间:2024-07-09 22:25:34

2.1.创建线程(pthread_create)

引入接口:pthread_create,用于创建一个新线程

参数说明

  • pthread_t *thread:这是一个指向 pthread_t 类型的指针,用于存储新创建的线程的标识符。通过这个标识符,你可以引用或操作这个线程。
  • const pthread_attr_t *attr:这是一个指向 pthread_attr_t 类型的指针,用于设置线程的属性,如堆栈大小、调度策略等。如果传递 NULL,则使用默认属性。
  • void *(*start_routine) (void *):这是新线程将要执行的函数的指针。该函数必须接受一个 void * 类型的参数并返回一个 void * 类型的值。这个函数的参数 arg 将被传递给新线程。(输入一个函数的地址)
  • void *arg:这是传递给 start_routine 函数的参数。

如果成功,pthread_create 返回 0;如果失败,则返回错误码。


2.2.线程等待(pthread_join)

引入接口:pthread_join

参数说明

  • pthread_t thread:这是要等待的线程的标识符(ID),该标识符是由 pthread_create 函数返回的。
  • void **retval:这是一个指向 void * 指针的指针,用于接收被等待线程的返回值。如果被等待的线程调用了 pthread_exit 并传递了一个返回值,或者简单地返回了一个值(对于从 void* 返回类型的线程函数),那么这个值就可以通过这个参数返回给等待的线程。如果对这个返回值不感兴趣,可以传递 NULL

如果成功,pthread_join 返回 0;如果失败,则返回错误码。


代码示例1:

线程的创建和等待:

#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>

void *threadrun(void *args)
{
    int cnt =10;
    while(cnt)
    {
        std::cout<<"new thread run ...,cnt: "<<cnt--<<std::endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t tid;
    int n = pthread_create(&tid,nullptr,threadrun,(void*)"thread 1");
    
    std::cout<<"main thread join begin..."<<std::endl;
    n= pthread_join(tid,nullptr);

    if(n==0)
    {
        std::cout<<"main thread wait success"<<std::endl;
    }
    return 0;
}

***一些问题***

问题1:mian和new线程谁先运行?不确定

问题2:我们期望谁最后退出?main thread,如何来保证呢?

join来保证,不join呢?会造成类似僵尸进程的问题

问题3:tid是什么样子的?

代码:以16进制的形式打印出来 

std::string PrintToHex(pthread_t &tid)
{
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%lx", tid);
    return buffer;
}
    std::string tid_str = PrintToHex(tid); // 我们按照16进行打印出来
    std::cout << "tid : " << tid_str << std::endl;

这个线程id是一个虚拟地址,后面再谈


问题4:全面看待线程函数传参,它可以传任意类型,当然也可以传类对象的地址,这意味着我们可以给线程传递多个参数,多种方法了

class ThreadData
{
public:
    std::string name;
    int num;
};
void *threadrun(void *args)
{
    //静态强转 
    ThreadData *td = static_cast<ThreadData*>(args);
    int cnt =10;
    while(cnt)
    {
        std::cout << td->name << " run ..." <<"num is: "<<td->num<< ", cnt: " << cnt-- << std::endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    ThreadData *td=new ThreadData();
    td->name ="thread-1";
    td->num = 1;
    int n = pthread_create(&tid,nullptr,threadrun,(void*)&td);
}

传类对象的时候最好是在堆上开辟,这样多个线程之间就不会互相干扰。


问题5:pthread_create第三个参数的返回值,该返回值是void*类型的,如果主线程想要获取线程的返回值,可以通过join函数获取(在线程没出错的情况下是能获取到的,如果某一个线程出错,主线程也是会跟着崩掉,因为线程出错误,是直接给整个进程发信号的,导致整个进程都挂掉了)

代码示例:返回一个类对象

#include <iostream>
#include <string>
#include <thread>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>


class ThreadData
{
public:
    int Excute()
    {
        return x + y;
    }
public:
    std::string name;
    int x;
    int y;
    // other
};

class ThreadResult
{
public:
    std::string print()
    {
        return std::to_string(x) + "+" + std::to_string(y) + "=" + std::to_string(result);
    }
public:
    int x;
    int y;
    int result;
};
std::string PrintToHex(pthread_t &tid)
{
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%lx", tid);
    return buffer;
}
void *threadRun(void *args)
{
    ThreadData *td = static_cast<ThreadData*>(args); // (ThreadData*)args
    ThreadResult *result = new ThreadResult();
    int cnt = 10;
    while(cnt)
    {
        sleep(3); 
        std::cout << td->name << " run ..." << ", cnt: " << cnt-- << std::endl;
        result->result = td->Excute();
        result->x = td->x;
        result->y = td->y;
        break;//跑一次退出
    }
    delete td;
    return (void*)result;
}
int main()
{
    pthread_t tid;
    ThreadData *td=new ThreadData();
    td->name="thread-1";
    td->x=10;
    td->y=20;
    int n = pthread_create(&tid, nullptr, threadRun, td);
   
    std::string tid_str = PrintToHex(tid); // 我们按照16进行打印出来
    std::cout << "tid : " << tid_str << std::endl;
  
    std::cout<<"main thread join begin..."<<std::endl;
    
    ThreadResult *result = nullptr; // 开辟了空间的!!!
    n = pthread_join(tid, (void**)&result); 
    if(n == 0)
    {
        std::cout << "main thread wait success, new thread exit code: " << result->print() << std::endl;
    }
    sleep(10);
    return 0;
}


2. 3.创建多线程  

下面是一段示例:

初步:创建线程id和线程name,保存所有线程的id信息,最后主线程回收每个线程

#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

const int num = 10;
std::string PrintToHex(pthread_t &tid)
{
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%lx", tid);
    return buffer;
}

void *threadrun(void *args)
{
    std::string name = static_cast<const char*>(args);
    while(true)
    {
        std::cout << name << " is running" << std::endl;
        sleep(1);
        break;
    }
    return args;
}
int main()
{
    std::vector<pthread_t> tids;
    for(int i = 0; i < num; i++)
    {
        // 1. 有线程的id
        pthread_t tid;
        // 2. 线程的名字
        char *name = new char[128];
        snprintf(name, 128, "thread-%d", i+1);
        pthread_create(&tid, nullptr, threadrun, /*线程的名字*/name);
        //3.保存所有线程id
        tids.push_back(tid);
    }
    
    for(auto tid:tids)
    {
        void*name=nullptr;
        pthread_join(tid,&name);
        std::cout<<(const char*)name<<"quit..."<<std::endl;
        delete (const char*)name;
    }

}
​

我们用vector储存线程id集