线程控制

一、创建线程:

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;
}
相关推荐
峥无7 小时前
Linux系统编程基石:静态库·动态库·ELF文件·进程地址空间全景图
linux·运维·服务器
用户2367829801688 小时前
从 chmod 755 说起:Unix 文件权限到底是怎么算的?
linux
Strugglingler8 小时前
【systemctl 学习总结】
linux·systemd·systemctl·journalctl·unit file
嵌入式×边缘AI:打怪升级日志9 小时前
100ASK-T113 Pro 开发板 Bootloader 完全开发指南
linux·ubuntu·bootloader
charlie11451419110 小时前
Linux 字符设备驱动:cdev、设备号与设备模型
linux·开发语言·驱动开发·c
handler0110 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
zhouwy11310 小时前
Linux进程与线程编程详解
linux·c++
我星期八休息11 小时前
IT疑难杂症诊疗室:AI时代工程师Superpowers进化论
linux·开发语言·数据结构·人工智能·python·散列表
切糕师学AI11 小时前
深入解析 Zsh 与 Oh-My-Zsh:打造高效现代化终端
linux·终端·zsh
切糕师学AI12 小时前
Ubuntu 下 Git 完全使用指南
linux·git·ubuntu