【APUE】线程1

1. 概念

在一个程序中,独立运行的程序片段叫做线程,利用它编程的概念就叫做多线程处理。一个程序至少有一个进程,一个进程至少有一个线程,如果把进程比作火车,那么一个线程就是这列火车的一节车厢。
典型的UNIX进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情。有了多个控制线程后,在程序设计师可以把进程设计成在同一时刻能够做不止一件事,每个线程处理各自独立的任务。
线程包含了表示进程内执行环境必须的信息:进程中标识线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量、线程私有数据。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全部内存和堆内存、栈以及文件描述符。

2. 线程标识

就像每个进程一个也有ID一样,每个线程也有一个线程ID。进程ID在整个系统中是唯一的,但线程ID不同,线程ID只在它所属的进程环境中有效。

函数 pthread_self

功能:获得自身的线程ID
函数原型

#include <pthread.h>
pthread_t pthread_self(void);
// 返回调用线程的线程ID
函数 pthread_equal

功能:比较两个线程ID是否相等
函数原型

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
// 若相等则返回非零值,否则返回0
3. 线程创建
!!!函数 pthread_create

功能:创建一个新的线程
函数原型

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
// 成功返回0,否则返回错误编号

参数说明
thread:thread 用来返回该线程的线程ID。由 tidp 指向的内存单元被设置为新创建线程的线程ID。
attr:定制不同的线程的属性。(设为NULL则创建默认属性的进程)
start_routine:start_routine 是一个函数指针,其指向的函数就是所创建的子线程要执行的任务(函数)。 start_routine指向的函数只有一个无类型指针参数arg(void *func(void *arg)),如果需要向该函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入
arg:传给所调用函数的参数(就是上一个参数里讲到的arg)。

4. 线程终止

如果进程中的任一线程调用了exit,_Exit 或者 _exit,那么整个进程就会终止。与此类似,如果信号的默认动作是终止进程,那么,把该信号发送到线程会终止整个进程。
单个线程可以通过下列三种方式退出,在不终止整个进程的情况下停止它的控制流。

  1. 线程只是从启动例程中返回,返回值时线程的退出码。
  2. 线程可以被统一进程中的其他线程取消。
  3. 线程调用 pthread_exit。
函数 pthread_exit

功能:终止调用线程
函数原型

#include <pthread.h>
void pthread_exit(void *retval);
函数 pthread_join

功能:与终止的线程连接
函数原型

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
// 成功则返回0,否则返回错误编号
函数 pthread_cancel

功能:请求取消同一进程中的其他线程
函数原型

#include <pthread.h>
int pthread_cancel(pthread_t thread);
// 成功则返回0,否则返回错误编号
函数 pthread_cleanup_push 和 pthread_cleanup_pop

功能:线程清理处理程序(pthread cleanup handler)
函数原型

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

当线程执行以下动作是调用清理函数(调用参数为arg,清理函数 routine 的调用顺序是由 pthread_cleanup_push 函数来安排的):

  1. 调用 pthread_exit 时。
  2. 响应取消请求时。
  3. 用非零 execute 参数调用 pthread_cleanup_pop 时。
5. 例子
一个例子:pthread_self() & pthread_create()

打印线程ID(printTID.c)

#include <pthread.h>
#include <stdio.h>
#include <error.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

pthread_t		ntid;

void printtids(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);
}

void *thr_fn(void *arg)
{
    printtids("new thread: ");
    return 0;
}

int main(int argc, char **argv)
{
    int    err;

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

    if(err != 0)
    {
        printf("cant't create thread: %s\n", strerror(err));
        return -1;
    }

    printtids("main thread: ");
    sleep(1);
    return 0;
}

运行结果
直接 gcc printTID.c 时会报错:

cxx@raspberrypi:~/za/aboutThread $ gcc printTID.c
/tmp/ccIRYKIh.o: In function `main’:

printTID.c:(.text+0x94): undefined reference to `pthread_create’
collect2: error: ld returned 1 exit status

原因是pthread不是linux下的默认的库,也就是在链接的时候,无法找到phread库中函数的入口地址,于是链接会失败。所以,在gcc编译的时候,要加 -pthread 参数。

cxx@raspberrypi:~/za/aboutThread $ gcc printTID.c -pthread
cxx@raspberrypi:~/za/aboutThread $ ./a.out
main thread: pid 18370 tid 1996349440 (0x76fde000)
new thread: pid 18370 tid 1994519664 (0x76e1f470)

两个例子:pthread_join() & pthread_create()

获得线程退出状态(threadExit.c)

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

void *thr_fn1(void *arg)
{
    printf("thread 1 running!\n");
    return ((void *)1);
}

void *thr_fn2(void *arg)
{
    printf("thread 2 running!\n");
    return ((void *)2);
}

int main(int argc, char **argv)
{
    pthread_t   tid1, tid2;
    void        *tret;

    if(pthread_create(&tid1, NULL, thr_fn1, NULL) != 0)
    {   
        printf("create thread 1 failed: %s\n", strerror(errno));
        return -1; 
    }   

    if(pthread_create(&tid2, NULL, thr_fn2, NULL) != 0)
    {   
        printf("create thread 2 failed: %s\n", strerror(errno));

运行结果

cxx@raspberrypi:~/za/aboutThread $ gcc threadExit.c -pthread
cxx@raspberrypi:~/za/aboutThread $ ./a.out
thread 1 running!
thread 2 running!
thread 1 exit code: 1
thread 2 exit code: 2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值