线程控制

一、创建线程:

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;
}
相关推荐
虾..1 小时前
Linux 软硬链接和动静态库
linux·运维·服务器
Evan芙1 小时前
Linux常见的日志服务管理的常见日志服务
linux·运维·服务器
hkhkhkhkh1233 小时前
Linux设备节点基础知识
linux·服务器·驱动开发
HZero.chen4 小时前
Linux字符串处理
linux·string
张童瑶4 小时前
Linux SSH隧道代理转发及多层转发
linux·运维·ssh
汪汪队立大功1234 小时前
什么是SELinux
linux
石小千4 小时前
Linux安装OpenProject
linux·运维
柏木乃一4 小时前
进程(2)进程概念与基本操作
linux·服务器·开发语言·性能优化·shell·进程
Lime-30904 小时前
制作Ubuntu 24.04-GPU服务器测试系统盘
linux·运维·ubuntu
百年渔翁_肯肯5 小时前
Linux 与 Unix 的核心区别(清晰对比版)
linux·运维·unix