线程控制

一、创建线程:

cpp 复制代码
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void *threadrun(void *args) // 新线程
{
    std::string name = (const char *)args;
    while (true)
    {
        std::cout << "我是新线程 name: " << name << std::endl;
        sleep(1);
    }

    return nullptr;
}

int main() // 函数向下执行创建新线程,新线程去执行threadrun,主线程继续向下执行
{
    pthread_t tid;                                                // 线程id
    pthread_create(&tid, nullptr, threadrun, (void *)"thread-1"); // 线程id,线程属性为空,要执行的方法,参数
    // 传进来字符串的起始地址就会交给要执行的方法
    while (true) // 主线程
    {
        std::cout << "我是主线程..." << std::endl;
        sleep(1);
    }

    return 0;
}
cpp 复制代码
test_thread:TestThread.cc
	g++ -o $@ $^ -lpthread
.PHONY:clean
clean:
	rm -f test_thread

不是系统调用,需引入第三方库才可以运行

1.关于调度的时间片问题:

创建的时候时间片要等分,为了创建的线程不影响进程切换

2.一个线程异常,导致整个进程奔溃

二、引入pthread库:

Linux系统中不存在真正意义的线程,使用轻量级进程模拟的,OS中,只有轻量级进程,所谓模拟线程是我们的说法。但是用户只认线程,为了使用线程并且方便轻量级进程的封装,就有了pthread库,把创建轻量级进程的接口封装起来,给用户提供一批创建线程的接口。从此以后,用户用线程就用pthread库接口,底层的轻量级进程的概念不用关心。Linux的线程实现,是在用户层实现的,称之为用户级线程,pthread称为原生线程库。

主线程要等待新线程执行完不然会造成类似僵尸进程的问题,内存泄漏。

创建一个线程指定一个任务完成之后结果返回:

cpp 复制代码
class Task
{
public:
    Task(int a, int b) : _a(a), _b(b) {}
    int Execute()
    {
        return (_a + _b);
    }
    ~Task() {}

private:
    int _a;
    int _b;
};

class Result
{
public:
    Result(int result) : _result(result)
    {

    }
    int Getresult() { return _result; }
    ~Result() {}

private:
    int _result;
};

void *routine(void *args)
{
    Task *t = static_cast<Task *>(args);
    sleep(1);
    Result *res = new Result(t->Execute());
    sleep(1);
    return res;
}

int main()
{
    pthread_t tid;
    Task *t = new Task(10, 20);
    int n = pthread_create(&tid, nullptr, routine, t);

    // int cnt = 5;
    // while(cnt--)
    // {
    //     std::cout << "main线程名字: " << std::endl;
    //     sleep(1);
    // }

    Result *ret = nullptr;
    pthread_join(tid, (void**)&ret); // 等待回收线程
    int n = ret->Getresult();

    std::cout << "新线程结束,运行结果: " << n << std::endl;

    delete t;
    delete ret;

    return 0;
}

三、线程终止:

线程的入口函数,进行return就是线程终止。

线程不能用exit终止,因为exit是用来终止进程的。

pthread_exit终止调用线程

需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的, 不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

四、线程等待:

为什么需要线程等待?已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。创建新的线程不会复用刚才退出线程的地址空间。

调用该函数的线程将挂起等待,直到id为thread的线程终⽌。thread线程以不同的方法终止,通过 pthread_join得到的终止状态是不同的。

总结如下:1. 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。 2. 如果thread线程被别的线程调用pthread_cancel异常终掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。 3. 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。 4. 如果对thread线程的终⽌状态不感兴趣,可以传NULL给value_ptr参数。

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>

void *routine(void *args)
{
    std::string name = static_cast<const char *>(args);
    int cnt = 10;
    while (cnt--)
    {
        std::cout << "线程名字:" << name << std::endl;
        sleep(1);
    }

    return (void *)10;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, routine, (void *)"thread-l");

    int cnt = 5;
    while (cnt--)
    {
        std::cout << "main线程名字:" << std::endl;
        sleep(1);
    }

    void *ret = nullptr;
    pthread_join(tid, &ret);

    std::cout << "新线程结束,退出码:" << (long long)ret << std::endl;
    return 0;
}

取消线程:主线程取消新线程,主线程是最后退的,因为要join,取消的时候要保证新线程已经启动。

线程被取消,推出结果为-1

五、线程分离:

默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。

如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。

不想让线程被等待,想让新线程结束时就自己退出,就设置为分离状态,但被分离的线程依旧可以使用进程的资源。

分离的线程依旧在进程的地址空间中,进程的所有资源被分离的线程都可以访问,可以操作。

cpp 复制代码
void *routine(void *args)
{
    std::string name = static_cast<const char *>(args);
    int cnt = 5;
    while (cnt--)
    {
        std::cout << "main线程名字:" << name << std::endl;
        sleep(1);
    }

    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, routine, (void *)"thread-l");

    pthread_detach(tid);
    std::cout << "新线程被分离" << std::endl;

    int cnt = 5;
    while (cnt--)
    {
        std::cout << "main线程名字:" << std::endl;
        sleep(1);
    }

    int n = pthread_join(tid, nullptr);
    if (n != 0)
    {
        std::cout << "pthread error" << std::endl;
    }
    else
    {
        std::cout << "pthread success" << std::endl;
    }

    return 0;
}
相关推荐
暴力求解30 分钟前
Linux基础开发工具 编译器gcc/g++
linux·运维·服务器
tan180°1 小时前
Linux网络IP(下)(16)
linux·网络·后端·tcp/ip
赖small强2 小时前
【Linux C/C++开发】第25章:元编程技术
linux·c语言·c++·元编程
一叶之秋14122 小时前
深入理解 Linux 环境变量与进程地址空间布局
linux·服务器
yuanManGan2 小时前
走进Linux的世界:虚拟内存空间
linux·运维·服务器
落羽的落羽2 小时前
【Linux系统】解明进程优先级与切换调度O(1)算法
linux·服务器·c++·人工智能·学习·算法·机器学习
代码游侠2 小时前
复习笔记——C语言指针
linux·c语言·开发语言·笔记·学习
百***69442 小时前
Linux下MySQL的简单使用
linux·mysql·adb
飞凌嵌入式3 小时前
飞凌嵌入式RK3568开发板的TFTP烧写文件系统指南
linux·嵌入式硬件·嵌入式