c多线程学习笔记(一):pthread

参考资料:http://blog.csdn.net/jiajun2001/article/details/12624923

初始化一个线程:pthread_create(pthread_t *thread, const pthread_attr_t attr, void (*start_func)(void *arg), void *arg)

头文件:#include <pthread.h>
初始化:int pthread_create(pthread_t *thread, const pthread_attr_t attr, void (*start_func)(void *arg), void arg);
解释:pthread_t thread:pthread句柄,初始化thread指向的线程。
const pthread_attr_t attr:attr句柄,初始化thread的设置。
void
(start_func)(void arg):函数指针,thread开始执行将会从此func作为入口执行,对函数参数类型和返回值做了要求,参数类型必须是void,返回参数类型也必须是void,保证任何类型的指针通过强制类型转换后都可以传入,并且在函数内再转换会原类型得到句柄,对外部作用域的变量或者对象进行操作,返回的void
参数必须指向作用域在线程外部也能操作,所以通常返回动态分配在堆中的变量和对象的指针或者返回传入参数指向的变量或者对象的指针。
void *arg:函数指针包括的参数,可以在线程启动时传入。注意自己转换类型,并且在函数中转换回原类型进行操作,对于有多个参数的函数,自己把参数封装成结构,通过结构类型的指针传入线程调用函数。
注意:在编译包含pthread.h头文件的多线程源代码时,需要链接libpthread.so的动态链接库,在编译指令后加 -lpthread

回收线程:int pthread_join(pthread_t pthread, void** func_ret);

解释:回收pthread所对应的线程,父线程进入等待状态,等待pthread线程执行完毕并回收其资源,线程入口函数的返回值void*的地址被返回,即func_ret,通过传入一个返回类型地址的参数,把这个指针变量取地址并强制转换成void**传入,最后该指针变量存储的就是指向返回值的指针,这个返回值变量要么存储在动态分配堆区,要么为thread入口函数传入的参数,即他的作用域必须要在父线程中可见。
e.g.:thread_ret_t *thread_ret;
int ret = pthread_join(thread, (void **)&thread_ret);
if (ret == 0) {
*thread_ret…; // thread_ret现在存储的是thread返回的对象的指针
}

分离线程:int pthread_detach(pthread_t pthread);

解释:分离子线程,子线程的运行脱离父线程的管控。

线程属性:pthread_attr_t类型

  • 初始化接口:int pthread_attr_init(pthread_attr_t *attr);
  • 销毁接口:int pthread_attr_destroy(pthread_attr_t *attr);
  • 属性简介
    • 绑定属性
    • 分离属性
    • 调度属性
    • 堆栈大小属性
    • 满栈警戒区属性

绑定属性

轻进程(LWP):轻进程和linux内核进程有相同的概念,属于内核直接调度的实体,一个轻进程可以控制一个或者多个线程,在操作系统中,LWP是一种实现多任务的方法,LWP和其他进程一样共享OS的逻辑地址空间以及其他系统资源,与线程相比,他有自己的进程号,有自己的父进程,并且只能由系统管理,而线程既可以由系统直接管理,也可以由程序本身定制。

默认设置,os决定将启动的n个线程绑定到m个轻进程上面,即绑定由os自己决定。用户设置,将那个线程绑定到相应的轻进程上,自定义设置。
被绑定的线程具有较高的响应速度,因为os调度的单位是进程,绑定进程后由该进程调度处理绑定在他身上的线程。
绑定属性接口:*int pthread_attr_setscope(pthread_attr_t attr, int scope);
scope:PTHREAD_SCOPE_SYSTEM(绑定态)
PTHREAD_SCOPE_PROCESS(非绑定态)
但是linux中的线程永远实绑定态的,而PROCESS标记会返回错误码ENOTSUP

分离属性

  • 接口:int pthread_attr_setdetachstate(pthread_t *attr, int detachstate);
    • detachstate:PTHREAD_CREATE_DETACHED | PTHREAD_CREATE_JOINABLE(default)

调度属性

算法

linux提供的调度算法有三种:轮询,先入先出,其他,这里轮询和先入先出是POSIX规定的实时调度算法,而linux默认的是其他调度算法。

  • 轮询:指时间片轮询当线程时间片用完系统从新分配线程新的时间并在就绪队列中等待,使得相同优先级的线程能够分配得到同等长度的时间片来轮转。
  • FIFO:先到先服务,先到的线程占据cpu,直到自己放弃或者优先级更高的线程到达。
  • 接口:int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
  • policy:SCHED_RR | SCHED_FIFO | SCHED_OTHER

优先级

linux优先级范围,0-99,越大代表优先级越高,只有在实时调度算法中优先级才有效,即SCHED_RRSCHED_FIFO,采用SCHED_OTHER的方式调度时,优先级恒为0.

接口:

struct sched_param {
    int sched_priority;
};
int pthread_attr_setschedparam(pthread_attr_t *attr, sched_param *param);

此外设置线程优先级必须在root账户下执行,并且也会放弃线程的继承权。

继承权

在创建新线程的时候子线程会继承父线程的调度属性,如果自己设置了调度属性,就会自动放弃父线程的调度属性。
接口:

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);

inheritsched:PTHREAD_INHERIT_SCHED | PTHREAD_EXPLICIT_SCHED。

堆栈大小属性

linux为每个线程默认分配了8M的栈空间,如果觉得不够用,可以通过修改堆栈大小属性来修改。
接口:

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

stacksize为堆栈大小,以字节为单位,分配时最好按照4K(32位系统)、2M(64位系统)的整数倍分配。

满栈警戒区属性

当我们修改了线程堆栈的大小,系统就会默认我们自己管理线程堆栈,将满栈警戒区取消掉。
接口:

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);

和设置线程堆栈大小属性一样,尽量位内存页面大小的整数倍,当设置为0时代表不设置满栈警戒区。

线程的本地存储

为了使每个线程在外部作用域内也能有自己独立的处理空间,使每个线程只需要处理自己的数据。

int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));
int pthread_key_destroy(pthread_key_t key);
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);

线程的同步

linux线程同步的机制主要有互斥锁和条件变量。

互斥锁

加锁的代码区域即为临界区,临界区应该尽可能小,不然程序的并行度会受到影响。互斥锁变量名为mutex。
接口:

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);     // 注:restrict是c语言对指针的修饰符,表明该指针所指向的对象只能通过该指针来修改其中的值。
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

条件变量

通过设置条件变量让一个线程等待另一个线程发出此条件的应答信息,有时候条件变量需要和互斥锁联合使用。
接口:

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const timespec *abstime);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

对于广播来说,所有在等待的线程有机会得到该信号然后继续执行,前提是要抢到互斥锁mutex。
wait操作前需要先抢到mutex,然后等待条件变量时会解锁mutex,供其他线程抢占,当wait到条件变量时,会从新抢占mutex上锁,在自己完成事件后再手动释放mutex。

线程原语简介

  • int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *arg), void *arg);
  • pthread_t pthread_self(void);
  • pid_t getpid(void);
  • void pthread_exit(void *retval);
  • int pthread_join(pthread_t thread, void **retval);
  • int pthread_cancel(pthread_t thread);
  • int pthread_detach(pthread_t thread);
  • int pthread_equal(pthread_t t1, pthread_t t2);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值