多线程程序是使用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
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)
{
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创建线程
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_param结构,当前只有一个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线程取消的定义
通常,线程在其主要功能退出时会自动终止,但是由于它从另一个线程接收到终止(取消)请求,因此也可能被迫终止.
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