APUE学习笔记——11 线程基础

线程标识

线程由线程号进行标识。线程号仅在线程所属的进程环境中有效。也就是说属于不同进程的两个线程可能线程号一样。

线程标识用结构体pthread_t tid表示。与线程Id相关的函数如下:

比较两个线程ID:

#include <pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2);
                              Returns: nonzero if equal, 0 otherwise

获取自身线程ID:

#include <pthread.h>
pthread_t pthread_self(void);
                         Returns: the thread ID of the calling thread

创建和终止进程:

创建线程:

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr,
                    void *(*start_rtn)(void *), void *restrict arg);
                                Returns: 0 if OK, error number on failure

tidp: 线程ID

attr:定制线程属性

start_rtn:新线程从start_rtn指向的函数开始执行

arg:传入start_rtn指向函数的参数

线程终止:

线程有三种终止方式:


1)从启动例程返回(return),返回值为线程退出码

2)被同进程的其他线程取消

3)调用pthread_exit

1)调用pthread_exit

#include <pthread.h>
void pthread_exit(void *rval_ptr);

启动例程调用pthread_exit 可以退出线程。rval_ptr可以被其他线程通过pthread_join访问到

#include <pthread.h>
int pthread_join(pthread_t thread,void **rval_ptr);
                             Returns: 0 if OK, error number on failure

pthread_join 使线程发生阻塞,知道thread指向的线程终止,rval_ptr用于获取终止线程的返回值。如果线程是通过被取消的方式结束,则返回值被置为PTHREAD_CANCELED。

2)被同进程其他线程取消

#include <pthread.h>
int pthread_cancel(pthread_t tid);
Returns: 0 if OK, error number on failure

3)线程的清理

线程可以构建线程清理程序栈来自定义线程清理程序。(栈:后进先出)

#include <pthread.h>
void pthread_cleanup_push(void (*rtn)(void *), void *arg);
void pthread_cleanup_pop(int execute);

在三种情况之一,线程清理程序栈被调用


a.线程调用pthread_exit

b.应答其他线程的cancellation请求

c. execute参数非0

具体使用见后面的example

#include "apue.h"
#include "myerr.h"
#include <pthread.h>
void
cleanup(void *arg)
{
        printf("cleanup: %s\n", (char *)arg);
}
void *
thr_fn1(void *arg)
{
        printf("thread 1 start\n");
        pthread_cleanup_push(cleanup, "thread 1 first handler");
        pthread_cleanup_push(cleanup, "thread 1 second handler");
        printf("thread 1 push complete\n");
        if (arg)
                return((void *)1);
        pthread_cleanup_pop(0);
        pthread_cleanup_pop(0);
        return((void *)1);
}
void *
thr_fn2(void *arg)
{
        printf("thread 2 start\n");
        pthread_cleanup_push(cleanup, "thread 2 first handler");
        pthread_cleanup_push(cleanup, "thread 2 second handler");
        printf("thread 2 push complete\n");
        if (arg)
                pthread_exit((void *)2);
        pthread_cleanup_pop(0);
        pthread_cleanup_pop(0);
        pthread_exit((void *)2);
}
int
main(void)
{
        int  err;
        pthread_t  tid1, tid2;
        void  *tret;
        err = pthread_create(&tid1, NULL, thr_fn1, (void *)1);
        if (err != 0)
                err_exit(err, "can’t create thread 1");
        err = pthread_create(&tid2, NULL, thr_fn2, (void *)1);
        if (err != 0)
                err_exit(err, "can’t create thread 2");
        err = pthread_join(tid1, &tret);
        if (err != 0)
                err_exit(err, "can’t join with thread 1");
        printf("thread 1 exit code %ld\n", (long)tret);
        err = pthread_join(tid2, &tret);
        if (err != 0)
                err_exit(err, "can’t join with thread 2");
        printf("thread 2 exit code %ld\n", (long)tret);
        exit(0);
}
           

执行结果

[email protected]:~/Windeal/apue$ ./exe
thread 2 start
thread 2 push complete
cleanup: thread 2 second handler
cleanup: thread 2 first handler
thread 1 start
thread 1 push complete
cleanup: thread 1 second handler
thread 1 exit code 1
thread 2 exit code 2
[email protected]:~/Windeal/apue$ 

时间: 2024-11-05 22:37:22

APUE学习笔记——11 线程基础的相关文章

APUE学习笔记——11 线程同步、互斥锁、自旋锁、条件变量

线程同步 同属于一个进程的不同线程是共享内存的,因而在执行过程中需要考虑数据的一致性. 假设:进程有一变量i=0,线程A执行i++,线程B执行i++,那么最终i的取值是多少呢?似乎一定是i=2:其实不然,如果没有考虑线程同步,i的取值可能是1.我们先考虑自加操作的过程:a,首先将内存中i的值copy到寄存器:b,对寄存器中i的copy进行自加:c,将寄存器中自加的结果返回到内存中.回到例子,如果线程A执行完abc三个步骤,线程B在执行者三个步骤,那么结果就应该为2.但是自加不是原子操作,假如执行

APUE 学习笔记(一) Unix基础知识

1. Unix 体系结构 内核的接口被称为系统调用 公用函数库构建在系统调用接口之上 应用软件既可以调用公用函数库,也可以直接进行系统调用 2. 文件和目录 目录操作函数:opendir---> readdir---> closedir struct dirent 结构体 stat 系统调用 3.程序.进程.线程 程序:存放在磁盘上.并处于某个目录中的一个可执行文件.使用exec系列函数将程序从磁盘读入存储器,并使其执行 进程:程序的执行实体.进程控制的3个函数:fork.exec.waitp

APUE学习笔记:第一章 UNUX基础知识

1.2 UNIX体系结构 从严格意义上,可将操作系统定义为一种软件(内核),它控制计算机硬件资源,提供程序运行环境.内核的接口被称为系统调用.公用函数库构建在系统调用接口之上,应用软件即可使用公用函数库,也可使用系统调用.shell是一种特殊的应用程序,它为运行其他应用程序提供了一个接口 从广义上,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并给予计算机以独有的特性(软件包括系统实用程序,应用软件,shell以及公用函数库等) 1.3  shell shell是一个命令行解

python基础教程_学习笔记11:魔法方法、属性和迭代器

魔法方法.属性和迭代器 在python中,有的名称会在前面和后面各加上两个下划线,这种写法很特别.它表示名字有特殊含义,所以绝不要在自己的程序中使用这种名字.在python中,由这些名字组成的集合所包含的方法叫做魔法(或称特殊)方法.如果对象实现了这些方法中的某一个,那么这个方法会在特殊的情况下被python调用,而几乎没有直接调用它们的必要. 准备工作 为了确保类是新型的,应该把赋值语句__metaclass__=type放在你的模块的最开始,或者(直接或间接)子类化内建类(实际上是类型)ob

APUE学习笔记:第七章 进程环境

7.1 引言 本章将学习:当执行程序时,其main函数是如何被调用的:命令行参数是如何传送给执行程序的:典型的存储器布局是什么样式:如何分配另外的存储空间:进程如何使用环境变量:各种不同的进程终止方式等:另外还将说明longjmp和setjmp函数以及它们与栈的交互作用:还将介绍研究进程的资源限制 7.2 main函数 C程序总是从main函数开始执行.当内核执行C程序时,在调用main前先调用一个特殊的启动例程.可执行程序文件将此启动例程指定为程序的起始地址——这是由连接编辑器设置的,而连接编

APUE学习笔记:第八章 进程控制

8.1 引言 本章介绍UNIX的进程控制,包括创建新进程.执行程序和进程终止.还将说明进程属性的各种ID-----实际.有效和保存的用户和组ID,以及他们如何受到进程控制原语的影响.本章还包括了解释器文件和system函数.本章最后讲述大多数UNIX系统所提供的进程会计机制.这种机制使我们能够从另一个角度了解进程的控制功能. 8.2 进程标识符 每个进程都有一个非负整型表示的惟一进程ID.因为进程标识符是惟一的,常将其用作其他标识符的一部分以保证其惟一性.虽然是惟一的,但是进程ID可以重用.(大

APUE学习笔记:第九章 进程关系

9.1 引言 本章将更详尽地说明进程组以及POSIX.1引入的会话的概念.还将介绍登陆shell(登录时所调用的)和所有从登陆shell启动的进程之间的关系. 9.1 终端登陆 系统管理员创建通常名为/etc/ttys的文件,其中每个终端设备都有一行,每一行说明设备名传递给getty程序的参数.当系统自举时,内核创建进程ID为1的进程,依旧是init进程.init进程使系统进入多用户状态.init进程读文件/etc/ttys,对每一个允许登陆的终端设备,init调用一次fork,所生成的子进程则

lua学习笔记11:lua中的小技巧

lua中的小技巧,即基础lua语言本身的特种,进行一个些简化的操作 一 巧用or x = x or v 等价于: if not x then x = v end 如果x为nil或false,就给他赋值为 二 三元运算符实现 a and b or c 类似C语言: a ? b : c and 的运算由优先级高于or lua学习笔记11:lua中的小技巧,布布扣,bubuko.com

APUE学习笔记:第四章 文件和目录

4.1 引言 本章将描述文件的特征和文件的性质 4.2 stat.fstat和lstat函数 #include<sys/stat.h> int stat(const char *restrict pathname,struct stat *restrict buf); int fstat(int filedes,struct stat *buf) int lstat(const char *restrict pathname,struct stat *restrict buf); 三个函数的返