linux系统下创建线程,C语言多线程(1)在Linux下创建和取消线程

0451abcfeb240a38a298efc708f9766f.png

多线程程序是使用C在Linux下开发的. Linux系统下的多线程遵循POSIX线程接口,称为pthread.

#include

int pthread_create(pthread_t *限制tidp,

const pthread_attr_t *限制属性,

void *(* start_rtn)(void),

无效*限制arg);

返回: 如果可以,返回0,失败时显示错误编号

通过限制修改的指针是在C99中新添加的: 通过限制修改的指针是最初访问该指针指向的对象的唯一方法. 仅当第二个指针基于第一个指针时,才可以存储对象. 采取. 对对象的访问仅限于由strict修改的指针表达式. 使用strict装饰的指针主要用于函数参数或指向由malloc()分配的内存空间. 限制数据类型不会更改程序的语义. 通过假设限制修改的指针是访问对象的唯一方法,编译器可以更好地优化某些类型的例程.

第一个参数是指向线程标识符的指针.

第二个参数用于设置线程属性.

第三个参数是线程运行函数的起始地址.

最后一个参数是运行函数的参数.

在以下程序中,我们的函数线程不需要参数,因此最后一个参数设置为空指针. 我们还将第二个参数设置为空指针,这将生成具有默认属性的线程. 成功创建线程后linux posix 线程池,该函数返回0. 如果不为0,则意味着线程创建失败. 常见的错误返回码是EAGAIN和EINVAL. 前者表示系统限制了新线程的创建,例如,线程数太大;后者表示第二个参数表示的线程属性值是非法的. 成功创建线程后,新创建的线程将运行由参数三和参数四确定的功能,而原始线程将继续运行下一行代码.

#include

#include

#include

#include

#include

A7Zrua.jpg

pthread_t ntid;

无效的printids(const char * s)

{

pid_t pid;

pthread_t tid;

pid = getpid();

tid = pthread_self();

printf(“%s pid%u tid%u(0x%x)\ n”,s,(unsigned int)pid,(unsigned int)tid,(unsigned int)tid);

}

无效*线程(无效* arg)

{

printids(“新线程: ”);

返回((void *)0);

}

int main()

{

int temp

if((temp = pthread_create(&ntid,NULL,thread,NULL))!= 0)

323cd7c0cc63278083ccbb07681cbd39.png

{

printf(“无法创建线程: %s \ n”,strerror(临时));

返回1;

}

printids(“主线程: ”);

睡眠(1);

返回0;

}

修改APUE2上的程序,然后编译.

结果错误:

pthread.c :(. 文字+ 0x85): 对“ pthread_create”的未定义引用

由于pthread库不是Linux系统的默认库,因此在连接时需要使用libpthread.a库,因此在使用pthread_create创建线程时,请将-lpthread参数添加到编译中:

gcc -o pthread -lpthread pthread.c

这是有关Posix线程编程的专栏. 在澄清概念的基础上,作者将详细介绍Posix线程库API. 本文是第一篇将介绍线程创建和取消的文章.

1.1线程和进程

与进程相比,线程是一个更接近执行主体的概念. 它可以在同一进程中与其他线程共享数据,但是具有自己的堆栈空间和独立的执行顺序. 在串行程序的基础上引入线程和进程是为了提高程序的并发性,从而提高程序的效率和响应时间.

线程和进程各有优缺点: 线程执行的开销很小,但是不利于资源的管理和保护;过程相反. 同时,线程适合在SMP机器上运行,而进程可以在机器之间迁移.

1.2创建线程

954b56887e747764743ea3ada7366e7c.png

POSIX使用pthread_create()函数创建线程. API定义如下:

intpthread_create(pthread_t *线程,pthread_attr_t * attr,

void *(* start_routine)(void *),void * arg)

与创建由fork()调用的进程的方法不同,pthread_create()创建的线程与主线程(即,调用pthread_create()的线程)的执行顺序不同. 运行start_routine(arg)函数. thread返回创建的线程的ID,attr是创建线程时设置的线程属性(请参见下文). pthread_create()的返回值指示线程创建是否成功. 尽管arg是void *类型的变量,但是它也可以作为任何类型的参数传递给start_routine()函数;同时,start_routine()可以返回void *类型的返回值,并且该返回值也可以是其他类型,并且可以通过pthread_join()获得.

1.3线程创建属性

pthread_create()中的attr参数是一个结构指针,该结构中的元素对应于新线程的运行属性,主要包括以下各项:

__ detachstate,指示新线程是否与进程中的其他线程不同步. 如果设置,则新线程无法与pthread_join()同步,并在退出时自行释放占用的资源. 默认值为PTHREAD_CREATE_JOINABLE状态. 创建并运行线程之后,也可以使用pthread_detach()设置此属性,并且一旦将其设置为PTHREAD_CREATE_DETACH状态(无论是在创建时还是在运行时设置),就无法将其恢复为PTHREAD_CREATE_JOINABLE状态.

__ schedpolicy,代表新线程的调度策略,主要包括SCHED_OTHER(常规,非实时),SCHED_RR(实时,循环)和SCHED_FIFO(实时,先进先出). out),默认值为SCHED_OTHER,后两项调度该策略仅对超级用户有效. 您可以使用pthread_setschedparam()在运行时进行更改.

__ schedparam,一种结构sched_pa​​ram结构,当前只有一个sched_priority整数变量,它表示线程的运行优先级. 该参数仅在调度策略是实时的(即SCHED_RR或SCHED_FIFO)时才有效linux posix 线程池,并且可以在运行时通过pthread_setschedparam()函数进行更改. 默认值为0.

__ Inheritedched,有两个值可供选择: PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED,前者指示新线程使用显式指定的调度策略和调度参数(即attr中的值),而后者指示继承调用者线程的值. 默认值为PTHREAD_EXPLICIT_SCHED.

__作用域,它表示线程之间CPU争用的范围,即线程优先级的有效范围. POSIX标准中定义了两个值: PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS,前一个意味着与系统中的所有线程争夺CPU时间,而后者意味着仅与同一进程中的线程争夺CPU. 当前,LinuxThreads仅实现PTHREAD_SCOPE_SYSTEM的值.

pthread_attr_t结构中有一些值,但未使用pthread_create()设置它们.

为了设置这些属性,POSIX定义了一系列属性设置函数,包括pthread_attr_init(),pthread_attr_destroy()和pthread_attr_get --- / pthread_attr_set ---与每个属性相关的函数.

1.4 Linux创建线程的实现

我们知道Linux线程实现是在核心外部执行的,并且该核心提供了用于创建进程的接口do_fork(). 内核提供了两个系统调用__clone()和fork(),并最终使用不同的参数调用do_fork()核心API. 当然,如果要实现线程化,则不存在对多进程(实际上是轻量级进程)共享数据段的核心支持. 因此,do_fork()提供了许多参数,包括CLONE_VM(共享内存空间),CLONE_FS(共享文件系统信息),CLONE_FILES(共享文件描述符表),CLONE_SIGHAND(共享信号句柄表)和CLONE_PID(共享进程ID),仅对核心进程,即进程0). 使用fork系统调用时,内核将调用do_fork()而不使用任何共享属性,并且该进程具有独立的运行环境. 当使用pthread_create()创建线程时,所有这些属性最终都设置为调用__clone(),并且这些参数全部都传递给核心中的do_fork(),因此创建的“进程”具有共享的操作环境,只有堆栈是独立的,并由__clone()传入.

Linux线程以轻量级进程的形式存在于内核中,具有独立的进程表条目,并且所有操作(如创建,同步和删除)均在内核外的pthread库中执行. pthread库使用管理线程(__pthread_manager(),每个进程是独立且唯一的)来管理线程的创建和终止,为线程分配线程ID,发送与线程相关的信号(例如Cancel)和主线程(pthread_create( ))调用方将通过管道将请求信息传递给管理线程.

2.1线程取消的定义

通常,线程在其主要功能退出时会自动终止,但是由于它从另一个线程接收到终止(取消)请求,因此也可能被迫终止.

fdc94154a1ef411f00daceec89c4a512.png

2.2线程取消的语义

线程取消的方法是向目标线程发送一个Cancel信号,但是如何处理Cancel信号则取决于目标线程本身,或者忽略它,或者立即终止,或者继续运行到Canceration-point(取消点),由不同的国家决定.

接收CANCEL信号的线程的默认处理(即创建线程的pthread_create()的默认状态)是继续运行到取消点,也就是说,将线程设置为CANCELED状态继续运行,仅运行到癌变点. 只有这样,您才能退出.

2.3取消点

根据POSIX标准,pthread_join(),pthread_testcancel(),pthread_cond_wait(),pthread_cond_timedwait(),sem_wait(),sigwait()和其他函数,以及read(),write()和其他系统调用会导致阻塞点,而其他pthread函数将不会导致癌变动作. 但是,pthread_cancel的手册页声称,由于LinuxThread库和C库的组合不佳,当前的C库函数不是Cancerion-point;但是,CANCEL信号将导致线程从阻塞的系统调用中退出并设置EINTR错误代码. 您可以在需要为癌化点的系统调用之前和之后调用pthread_testcancel(),以实现POSIX标准所需的目标,这是以下代码段:

pthread_testcancel();

retcode =读取(fd,缓冲区,长度);

pthread_testcancel();

2.4程序设计注意事项

如果线程处于无限循环中,并且在循环主体中没有到达取消点的必要路径,则该线程无法被另一个外部线程的取消请求终止. 因此,应将pthread_testcancel()调用添加到此类循环体的必要路径.

2.5与线程取消有关的pthread函数

int pthread_cancel(pthread_t线程)

将终止信号发送到线程线程,如果成功,则返回0,否则为非零值. 成功传输并不意味着线程将终止.

int pthread_setcancelstate(整数状态,整数*旧状态)

将此线程的响应设置为“取消”信号. 该状态具有两个值: PTHREAD_CANCEL_ENABLE(默认值)和PTHREAD_CANCEL_DISABLE,它们指示在接收到信号且忽略CANCEL信号之后设置CANCLED状态. 如果old_state不为NULL,则将其保存. 输入原始的“取消”状态以还原.

int pthread_setcanceltype(int类型,int *旧类型)

设置该线程的取消动作的执行时间. 该类型具有两个值: PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS. 仅当“取消”状态为“启用”时才有效,这意味着在接收到信号后,它将继续运行到下一个取消点,然后退出并立即执行. 取消操作(退出);如果oldtype不为NULL,则存储出厂时取消动作类型的值.

void pthread_testcancel(void)

检查此线程是否处于“取消”状态,如果是,则取消操作,否则直接返回.

---------------------

作者: 科什

本文来自电脑杂谈,转载请注明本文网址:

http://www.pc-fly.com/a/jisuanjixue/article-172369-1.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值