天天看点

线程的创建

        线程是一种使程序在同一时间做多件事的机制,和进程一样是并发执行的。linux内核调度为每个线程分配一个时间片,使用完后等待下次调度。和进程相比,线程是一种更小的执行单位。

        每个进程启动后都会有一个线程在运行,称为主线程,可以在主线程中启动多个子线程,这些线程在同一个进程中,不同线程在给定时间内执行不同的代码片段。

        我们可以fork一个子进程,这个子进程就是对父进程的一个copy,包括系统分配的各种资源:虚拟内存、文件描述符等。如果在子进程关闭文件描述符,不会影响父进程对其的读写。但线程不同,每个线程都共享同一内存、文件描述符、以及其他资源。在一个线程中关闭文件描述符,其他的线程都不能读写。

        在任何一个线程中调用exec,所有线程都会停止,并且当前线程所在的进程会被exec传递的程序替换。

1.线程创建

        所有与线程相关的函数和数据类型都在<pthread.h>中声明,但线程函数没有被包含进C标准库中,因此,调用了线程相关API后,编译时需要添加线程库:libpthread,或者-lpthread

       每个线程用一个唯一的ID表示,称为线程id,编程中类型为pthread_t.

        创建一个线程很简单,只需调用以下函数即可,创建之后线程会等待系统调用随时会启动。

参数介绍:

 thread :线程的ID,一个pthread_t类型的指针

attr: 线程的属性,一般赋值为NULL,表示使用默认值

start_routine :线程函数,在线程创建后需要执行的代码。一个普通函数,返回值、参数类型都是void*。这样可以传递任何类型的数据,只需将数据结构的指针传递,然后接收 到时强制转换。

arg :线程函数start_routine的参数

创建两个线程,分别打印“hello”和“world”,主线程打印"main"

        以上代码中创建两个线程,线程函数相同只是传递的参数不同,运行之后可以看到打印"main"个数每次都是10个,“hello”,"world"个数不够10个。只是因为main线程在两个子线程没有退出之前结束。

        要等待子线程都退出之后main线程在退出,和进程中的wait相似,线程中使用pthread_join();

thread: 等待退出线程的id

retval: 线程退出时的返回值,通过指针的方式传递个*retval,如果调用pthread_join时指定的线程已经退出,*retval 会返回PTHREAD_CANCLED

        一个线程的退出可以通过两种方式:1.等待线程函数执行到return返回 ;2.在线程中执行void pthread_exit(void *retval),retval为线程返回的值。无论用哪种返回方式,返回值都会在pthread_join的参数retval中获取。

如下程序,创建两个线程调用同一个函数,对线程函数传递的参数不同其返回值也不同:#include <pthread.h>

        如以上示例,通常一个函数可能被多个线程调用,有时候函数需要知道自己被哪个进程正在运行,可以在函数中调用:pthread_t pthread_self(void)返回正在运行函数的线程id

        如果在一个线程中调用pthread_join并将自己的id作为参数,函数会立刻出现错误,并返回EDEADLK。为了避免一个线程pthread_join自己的id,可以这样:

pthread_equal 函数定义:

2.线程的joinable和detach状态

        joinable状态的线程,当线程结束之后不会自动释放资源,直到其他线程调用pthread_join该线程的返回值时才会释放。

        detach 状态的线程,线程结束之后会自动释放资源,其他线程不能调用pthread_join获取他的返回值。

        线程这两种状态由创建时pthread_create传递的属性attr参数来控制,默认情况下为joinable状态。

将线程设置为detach状态:

在这里,多个线程创建可以使用同一个attr,使用完后要用pthread_attr_destroy删除,下次用时在phtread_attr_init

注:一个线程创建时是joinable状态,可以用pthread_detach将其转换成detach状态,反之,不可以。

继续阅读