Linux高级编程6 - 线程

pthread 线程:

        pthread 是 POSIX 线程 (POSIX Threads) 的缩写,提供了一组用于多线程编程的库函数。这些函数允许程序员在 C/C++ 代码中创建和管理多个并发执行的线程,从而可以在多核处理器上更高效地执行任务。使用线程要包含#include <pthread.h>。并且在编译是加上 -lpthread。

  进程是系统中最小的资源分配单位。 线程是系统中最小的执行单位。

   命令:ps -eLf (全部打印)或ps -eLo pid,ppid,lwp,stat,comm(部分打印)

基本概念

        线程:线程是程序执行的基本单位,一个程序可以包含多个线程,每个线程执行不同的任务,但共享同一进程的地址空间。

        主线程:程序启动后自动创建的第一个线程,通常是 main 函数执行的线程。

        子线程:由主线程或其他线程创建的线程。 

线程的优点: 比多进程节省资源,可以共享变量。

进程与线程的区别:

    资源:线程比进程多了共享资源(线程存在竞争问题)。进程可以通过(IPC进程通信实现数据共享)、线程又具有部分私有资源。进程间只有私有资源没有共享资源。
    空间:进程空间独立,不能直接通信。线程可以共享空间,可以直接通信。生成进程是要生成3G的内存的空间(code区、data区、堆区、共享区、栈区)。而线程只会生成栈的空间(8M),其它数据共享。在多线程中使用exit的话回结束子线程。只保留一个线程。

   使用范围:进程适应于复杂任务,线程适用于简单重复性操作多的任务。

1、创建线程         pthread_create 函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

参数:

        thread:指向保存新线程 ID 的变量。

        attr:线程属性,一般传递 NULL 表示默认属性。

        start_routine:新线程执行的函数,这个函数的返回值是 void* 类型,参数也是 void* 类型。

        arg:传递给 start_routine 的参数。

返回值:成功 0; 失败 错误码

        注意:一次pthread_create执行只能创建一个线程。每个进程至少有一个线程称为主线程。主线程退出则所有创建的子线程都退出。 主线程必须有子线程同时运行才算多线程程序。 线程id是线程的唯一标识,是CPU维护的一组数字。pstree 查看系统中多线程的对应关系。多个子线程可以执行同一回调函数。

2、等待线程结束         pthread_join 函数

 int pthread_join(pthread_t thread, void **retval);

参数:

        thread:要等待的线程 ID。

        retval:用于获取线程的返回值。

3、 终止线程         pthread_exit 函数与pthread_cancel函数

        pthread_exit pthread_cancel 是 pthread 库中用于控制线程终止的两个函数。

前者子线程自行退出,后者主线程请求结束一个线程。但是这两个函数都不会释放子进程栈的空间。

void pthread_exit(void *retval);

         参数:retval:指定线程的返回值,该值会传递给 pthread_join 函数的 retval 参数。

         pthread_exit 用于显式终止调用它的线程。调用这个函数会使得线程正常结束,并且可以传递一个返回值给调用 pthread_join 的线程。需要注意的是,调用 pthread_exit 不会终止整个进程,只会终止当前线程。

int pthread_cancel(pthread_t thread);

        参数:thread:要取消的线程的 ID。

        返回值:成功 0,失败 -1;

        pthread_cancel 用于请求取消一个指定的线程。这个函数不会立即终止线程,而是发送一个取消请求。被取消的线程可以选择响应或忽略这个请求,具体取决于线程的取消状态和类型。

总结:

        pthread_exit:用于线程自身主动退出。线程可以返回一个值供 pthread_join 处理。适用于正常终止线程的场景。

        pthread_cancel:用于请求终止另一个线程。线程的终止取决于其取消状态和类型,可能不立即生效。适用于需要主动取消长时间运行或被卡住的线程。

4、线程回收

        pthread_detach pthread_join 都是用于管理线程生命周期的函数,它们的主要功能是处理线程的退出和资源回收,但它们的用途和使用方式不同。

int pthread_join(pthread_t thread, void **retval);

        thread:要等待的线程的 ID。

        retval:用于获取目标线程的返回值,如果不需要获取返回值可以传递 NULL。

       pthread_join 函数用于等待一个线程的结束,并回收该线程的资源。调用 pthread_join 的线程将被阻塞,直到目标线程结束。

#include <stdio.h>
#include <pthread.h>
void* thread_func(void* arg) {
    printf("Thread is running\n");
    pthread_exit((void*) 0); // 线程正常退出
}
int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, thread_func, NULL);

    void* retval;
    pthread_join(thread, &retval); // 等待线程退出,并获取返回值
    printf("Thread exited with code %ld\n", (long)retval);

    return 0;
}

int pthread_deatch() 函数

int pthread_detach(pthread_t thread);

          参数:thread:要分离的线程的 ID。

         函数用于将一个线程的状态设置为“分离状态(detached state)”。在分离状态下,线程结束时会自动释放其占用的资源,而不需要其他线程通过 pthread_join 来显式回收。该子线程结束后,操作系统释放该线程的资源, 需要通过主线程来释放PCB资源 。

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

void* thread_func(void* arg) {
    printf("Detached thread running\n");
    sleep(2); // 模拟一些工作
    printf("Detached thread finished\n");
    return NULL;
}

int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, thread_func, NULL);

    pthread_detach(thread); // 设置线程为分离状态

    // 主线程继续执行
    printf("Main thread finished\n");
    sleep(3); // 给分离线程足够的时间完成

    return 0;
}

5、线程清理函数

        线程清理函数是在线程退出时自动调用的函数。它用于释放线程在运行过程中申请的资源,确保程序不会出现资源泄漏,在大型项目中子线程申请的资源可能会在别的函数里使用,所以不可能该子线程结束了就清除资源,应该在其它地方使用后,统一清除这些资源才用这2个函数清除资源pthread_cleanup_push 和 pthread_cleanup_pop。

 pthread_cleanup_push()

        这个函数用于注册一个清理函数,当线程通过调用 pthread_exit、响应 pthread_cancel 或者在线程中引发取消点时,注册的清理函数会被调用

void pthread_cleanup_push(void (*routine)(void *), void *arg);
routine:清理函数的指针。
arg:传递给清理函数的参数

pthread_cleanup_pop()

void pthread_cleanup_pop(int execute);
execute,非0  执行清理函数
0 ,不执行清理

这个函数用于调用清理函数,并且可以选择性地执行该清理函数。
 

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

void cleanup(void* arg) {
    printf("Cleanup: %s\n", (char*)arg);
}

void* thread_func(void* arg) {
    pthread_cleanup_push(cleanup, "Thread Exiting");  // 注册清理函数

    printf("Thread is running\n");
    sleep(2);  // 模拟一些工作

    // 使用 cleanup pop 来控制是否调用清理函数
    pthread_cleanup_pop(1);  // 传递 1,执行清理函数

    return NULL;
}

int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, thread_func, NULL);

    pthread_join(thread, NULL);  // 等待线程结束
    return 0;
}

        pthread_cleanup_push 和 pthread_cleanup_pop 必须成对出现,并且通常在同一代码块内使用

        当线程退出时,无论是正常退出还是由于取消请求而退出,pthread_cleanup_push 注册的清理函数都会被执行。

6、线程传值。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
typedef struct 
{
    char buf[50];
    int num;

}ARG;
void* th(void* arg)
{
    ARG* tmp = (ARG*)arg;

    strcat(tmp->buf,"123456");
    tmp->num +=10;
    return tmp;
}
int main(int argc, char *argv[])
{

    ARG arg={0};
    bzero(&arg,sizeof(arg));
    strcpy(arg.buf,"hello");
    arg.num = 20;
    pthread_t tid;
    pthread_create(&tid,NULL,th,&arg);
    void* ret=NULL;
    pthread_join(tid,&ret);
    printf("ret %s  %d\n",((ARG*)ret)->buf,((ARG*)ret)->num);
    //free(ret);
    return 0;
}

        这个程序通过创建一个线程来处理数据,然后主线程等待子线程完成并获取结果,最后输出处理后的数据。代码展示了基本的多线程操作和线程间数据共享的方式

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值