多线程--初阶必看

多线程

多线程定义

一个进程可以包含多个线程,所有线程都执行同一个程序。这些线程共享相同的全局内存(数据段和堆段),但每个线程都有自己的堆栈用于存储各自的局部变量。

使用多线程

要使用多线程,需要引用#include <pthread.h>头文件,且编译时候需要链接libpthread.so库。 具体编译指令:

gcc pthread_test.c -o pthread_test -lpthread

线程属性

线程属性:绑定属性、分离属性、调度属性、堆栈大小属性、满栈警戒区大小属性。

int pthread_attr_init(pthread_attr_t *attr);  
int pthread_attr_destory(pthread_attr_t *attr);

分离属性

线程是能够合并和分离的,分离属性则是在线程 创建之前,就线程属性设置为分离。如果调用了,则没必要调用pthread_join()pthread_detach()回收线程资源了。 线程分离的接口定义:

pthread_attr_setdetachstat(pthread_attr_t *attr, int detachstate);
// detachstate: PTHREAD_CREATE_DETACHED(分离的) \ PTHREAD_CRESTE_JOINABLE(可合并的,默认属性)

具体工程代码

#include <pthread.h>
int main(int argc, char *argv[])
{
    phtread_attr_t attr;
    pthread_t thread;
//  ...
    pthread_attr_init(&attr);
    pthread_attr_setdetachstat(&attr, PTHREAD_CREATE_DETACHED);
    phtread_create(&th, &attr, thread, NULL);

}

堆栈大小属性

要知道线程的主函数与main函数中的主线程,分别有自己的堆栈。虽然同一个进程的线程之间是共享内存空间,但每个线程分别拥有自己独立的堆栈用于存放各自的局部变量。Linux默认为每个线程分配8MB的堆栈空间。可通过pthread_attr_setstacksize()进行扩容。

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);  
// stacksize: 堆栈大小,以字节为单位。线程堆栈小于16kb,尽量按照内存页面大小整倍数分配。[4KB(32位系统)或2MB(64位系统].够用尽量不用乱动。

创建线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); 

// thread:线程句柄
// attr:线程属性,若使用线程默认属性可传NULL,也可上面的介绍的线程属性进行修改。
// start_routine:线程入口函数
// arg: 线程函数的参数
// return: 0,代表成功,其它值代表创建失败

退出线程

线程函数结束时,调用pthread_exit可以安全退出

void pthread_exit( void* retval );
// retval:pthread_exit 将通过 retval 参数向线程的回收者传递其退出信息

结束线程

pthread_join()函数,以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。 需要注意的是,如果主线程中没有调用phtread_join,一旦主线程很快结束,将会直接使整个进程结束。使得创建的线程还没开始就被迫结束。解决这个问题,可以将线程进行分离。或者在主线程调用phtread_join,阻塞线程,直到被回收的线程结束。

int pthread_join(pthread_t thread, void **retval);
// thread:线程ID
// retval:用户定义的指针,用来存储被等待线程的退出返回值。
// return: 0,返回成功,失败返回错误码
// EDEADLK (error : dead lock)  可能引起死锁。如两个线程互相针对对方调用pthread_join,或线程对自身调用 pthread_join
// EINVAL (error : invalid) 目标线程是不可回收的,或者已经有其他线程在回收该目标线程
// ESRCH    目标线程不存在

线程分离

线程分离是将线程资源的回收工作交由系统自动来完成,也就是说当被分离的线程结束之后,系统会自动回收它的资源。

创建子线程前分离

可以通过上面的介绍的分离属性pthread_attr_setdetachstat(&attr, PTHREAD_CREATE_DETACHED);

子线程中分离

pthread_detach(pthread_self());

主线程设置子线程分离

pthread_detach(pid)pid为子线程的线程号 注意一旦子线程设置为线程分离,是不能调用pthread_join函数的

int pthread_detach(pthread_t thread);
// return :
// EINVAL :thread 不是 joinable thread。
// ESRCH :找不到线程ID所标识的线程。

Jia Feng

我喜欢的东西很贵,想去的地方很远,朝着目标前进。虽然苦,但是我还是会选择那种滚烫的人生

`