Linux线程(一)--- 线程基础

Linux线程(一)--- 线程基础,第1张

Linux线程(一)--- 线程基础

1.  线程的概念

        在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”。一切进程至少都有一个执行线程。

2.线程的优点

        1)通过为每种事件类型的处理分配单独的线程,能够简化处理异步时间的代码。

        2)多个线程可以自动共享相同的存储地址空间和文件描述符。

        3)有些问题可以通过将其分解从而改善整个程序的吞吐量。

        4)交互的程序可以通过使用多线程实现相应时间的改善,多线程可以把程序中处理用户输入输出的部分与其它部分分开。

3.线程的缺点

        线程也有不足之处。编写多线程程序需要更全面更深入的思考。在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的。调试一个多线程程序也比调试一个单线程程序困难得多。

4.线程的结构

        线程包含了表示进程内执行环境必需的信息,其中包括进程中标识线程的线程 ID,一组寄存器值、栈、调度优先级和策略、errno 变量以及线程私有数据。

        进程的所有信息对该进程的所有线程都是共享的(但通常我们在设计时,一个线程不会去访问与它无关的数据或代码的),包括可执行的程序文本,程序的全局内存和堆内存、栈以及文件描述符。

5.线程标识

        就像每个进程有一个进程 ID 一样,每个线程也有一个线程 ID,进程 ID 在整个系统中是唯一的,但线程不同,线程 ID 只在它所属的进程环境中有效。线程 ID 用 pthread_t 数据类型来表示,实现的时候可以用一个结构来代表 pthread_t 数据类型,所以可以移植的 *** 作系统不能把它作为整数处理。因此必须使用函数来对来对两个线程 ID 进行比较。

6.  线程的创建

6.1 pthread_create函数

功能:创建一个新的线程

原型:

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

参数:

thread:返回线程ID

attr:设置线程的属性,attr为NULL表示使用默认属性

start_routine:是个函数地址,线程启动后要执行的函数

arg:传给线程启动函数的参数

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

        pthread_creat 成功返回时, thread指向的内存单元被设置为新创建线程的线程ID。attr 参数用于定制各种不同的线程属性。可以把它设置为 NULL,创建默认的线程属性。新创建的线程从 start_routine 函数的地址开始运行,该函数只有一个无类型指针参数 arg。如果需要向 start_routine 函数传递的参数不止一个,那么需要把这些参数放到一个结构体中,然后把这个结构的地址作为 arg 参数传入。

        调用pthread_create()时会在用户空间创建一个线程同时也会在内核空间创建与之对应的线程。

        用户空间的线程:负责执行线程的创建、销毁等 *** 作。

        内核空间的线程:负责调度。

6.2 返回线程ID

pthread_self函数

功能:返回线程ID

原型:

pthread_t pthread_self(void);

返回值:成功返回0

6.3  pthread_create函数应用举例

#include 

void printids(const char *s)
{

printf("%s pid:%u tid:%u n", s,getpid(),pthread_self());

}

void *thr_fn(void *arg)
{

    printids("new thread: ");

}

int main()
{

    int err;

    pthread_t tid;

    err=pthread_create(&tid,NULL,thr_fn,NULL);

    if(err=0)

        printf("can’t create thread:%sn",strerror(err));

    printids("main thread: ");

    sleep(1);

    exit(0);

}

关于进程的编译我们都要加上参数 –lpthread 否则提示找不到函数的错误。具体编译方法是:

make –lpthread –o gettid gettid.c

运行结果为

main thread: pid 14954 tid 134529024

new thread: pid 14954 tid 134530048

7.  线程退出

        线程是依进程而存在的,当进程终止时,其所有的线程也就终止了。当然也有在不终止整个进程的情况下中止线程。

        1)线程从线程执行的函数中返回,返回值是线程的退出码。

        2)线程可以被同一进程中的其他线程取消。

        3)线程调用 pthread_exit 自己退出。

7.1  pthread_exit函数

功能:线程终止

原型:

void pthread_exit(void *value_ptr);

参数:

value_ptr:value_ptr不要指向一个局部变量。

返回值:无返回值。

7.2  pthread_join函数

功能:或等线程的中止状态

原型:

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

参数:

thread:线程ID

retval:它指向一个指针,后者指向线程的返回值

参数:成功返回0,失败返回错误码

        当一个线程通过调用 pthread_exit 退出或者简单地从启动历程中返回时,进程中的其他线程可以通过调用 pthread_join 函数获得进程的退出状态。调用 pthread_join 进程将一直阻塞,直到指定的线程调用 pthread_exit,从启动例程中或者被取消。

        如果线程只是从线程执行的函数中返回,retval 将包含返回码。

7.3  线程退出函数应用举例

#include 
#include 

void *thr_fn1(void *arg)
{
    printf("thread 1 returningn");
    return((void *)1);
}

void *thr_fn2(void *arg)

{

    printf("thread 2 exitingn");

    return((void *)2);

}

int main()
{
    pthread_t tid1,tid2;
    void *tret;
    pthread_create(&tid1,NULL,thr_fn1,NULL);
    pthread_create(&tid2,NULL,thr_fn2,NULL);
    pthread_join(tid1,&tret);
    printf("thread 1 exit code %dn",(int)tret);
    pthread_join(tid2,&tret);
    printf("thread 2 exit code %dn",(int)tret);
    exit(0);

}

运行结果:
thread 1 returning
thread 2 exiting
thread 1 exit code 1
thread 2 exit code 2 

8.  线程分离

pthread_detach函数

功能:使线程进入分离状态。

原型:

int pthread_detach(pthread_t thread);

参数:

thread:线程ID

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

        线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下,线程的终止状态会保存到对该线程调用 pthread_join,只有当 pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。如果线程已经处于分离状态,那么它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。当线程被分离时,并不能用 pthread_join 函数等待它的终止状态。对分离状态的线程进行pthread_join 的调用会产生失败,返回 EINVAL.pthread_detach 调用可以用于使线程进入分离状态。

9.  线程取消

pthread_cancel

功能:取消一个执行的线程

原型:

int pthread_cancel(pthread_t thread);

参数:

thread:线程ID

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

        在默认的情况下,pthread_cancel 函数会使由 thread标识的线程的行为表现为如同调用了参数为 PTHEAD_CANCELED 的 pthread_exit 函数。但是,线程可以选择忽略取消方式和控制取消方式。pthread_cancel 并不等待线程终止,它仅仅提出请求。

10.  线程进阶(先mark,待后续学习):

10.1 线程属性

        线程具有属性,用 pthread_attr_t 表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。我们用 pthread_attr_init 函数对其初始化,用 pthread_attr_destroy 对其去除初始化。

10.2 线程的分离状态

        线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。

可参考:linux中pthread_join()与pthread_detach()详解

linux中pthread_join()与pthread_detach()详解_魏波-CSDN博主-CSDN博客_pthread_detach

10.3 线程的继承性

        函数 pthread_attr_setinheritsched 和 pthread_attr_getinheritsched 分别用来设置和得到线程的继承性。

10.4 线程的调度策略

        函数 pthread_attr_setschedpolicy 和 pthread_attr_getschedpolicy 分别用来设置和得到线程的调度策略。

10.5 线程的调度参数

        函数 pthread_attr_getschedparam 和 pthread_attr_setschedparam 分别用来设置和得到线程的调度参数。

10.6 线程的作用域

        函数 pthread_attr_setscope 和 pthread_attr_getscope 分别用来设置和得到线程的作用域。

10.7 线程堆栈的大小

        函数 pthread_attr_setstacksize和 pthread_attr_getstacksize分别用来设置和得到线程堆栈的大小。

10.8 线程堆栈的地址

        函数 pthread_attr_setstackaddr 和 pthread_attr_getstackaddr 分别用来设置和得到线程堆栈的位置。

10.9 线程栈末尾的警戒缓冲区大小

        函数 pthread_attr_getguardsize 和 pthread_attr_setguardsize 分别用来设置和得到线程栈末尾的警戒缓冲区大小。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/3970171.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-10-21
下一篇 2022-10-21

发表评论

登录后才能评论

评论列表(0条)

保存