线程零碎知识总结

在启动程序时,产生的进程只有单条线程。而创建线程时,每个线程都有一个属于自己的大小固定的线程栈。

通过int pthread_create(pthread_t* thread,const pthread_attr_t* attr,void*(*start)(void*),void* arg);可以创建一条新线程。返回0表示成功,正整数表示错误。

 

 

线程ID:

每个线程都会有一个唯一的标识,可以通过pthread_t pthread_self(void);来获取自己的线程ID。

通过pthread_equal(pthread_t t1,pthread_t t2)检查ID是否相同,返回正整数表示相同。

 

线程的分离:

当不需要关心线程的返回状态,只希望系统在线程终止后自动清理,可以调用pthread_detach(pthread_t thread)传入指定线程的标识符,将线程标记为分离状态。

pthread_detach(pthread_self())可以自行分离,分离后就再也无法回到可连接状态了。

 

连接已终止的线程

函数pthread_join(pthread_t thread,void** retval)等待由thread标识的线程终止,retval保存返回值的拷贝。需要注意的是,如果向pthread_join()传入一个之前已经连接过的线程ID,将会导致无法预知的行为,因为线程ID会被重用。此外,如果线程并未分离,则必须进行连接,否则将产生僵尸线程,僵尸线程如果积累过多,将再也无法创建新线程。

 

 

终止线程:

线程执行函数里执行return,返回指定值。

线程调用pthread_exit(void* retval);retval指定了线程的返回值,但指向内容不能分配在线程栈中,因为线程终止后将无法确认线程栈的内容是否有效(系统可能将这部分区域分配给另一个线程栈使用 )如果主线程调用了pthread_exit(),那么其他线程将继续运行。

调用pthread_cancel()

任意线程调用exit()或者主线程执行return语句,会导致进程中所有线程立即终止。

 

 

线程同步:互斥量和条件变量

互斥量:多线程编程中需要注意的是多个线程不会同时修改同一个变量,不会读取一个正在由其他线程修改的变量。为了避免此类问题,必须使用互斥量来确保同时仅有一个线程可以访问共享资源。

互斥量有两种状态:已锁定locked和未锁定unlocked。任何时候,至多只能有一个线程可以锁定该互斥量。试图对已经锁定的某一互斥量再次加锁,会出现线程阻塞直到获得锁或者报错。

静态分配互斥量:pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

加锁:int pthread_mutex_lock(pthread_mutex_t* mutex);如果调用加锁的线程本身就已经锁了互斥量,可能会导致线程陷入死锁或者调用失败返回EDEADLK错误。

解锁:   int pthread_mutex_unlock(pthread_mutex_t* mutex);对处于未锁定状态的互斥量进行解锁或者解锁由其他线程锁定的互斥量将会出错。

 

动态初始化互斥量:int pthread_mutex_init(pthread_mutex_t* mutex,const pthread_mutexattr_t* attr);当不再需要互斥量后,使用pthread_mutex_destroy()将其销毁。

 

条件变量:允许一个线程在某个共享资源状态变化时通知其他线程,并让其他线程阻塞直到接受到通知。主要操作是发送信号signal(通知别的线程,共享资源状态改变)和等待wait(阻塞直到通知到达)。

静态分配条件变量:pthread_cond_t cond = PTHREAD_COND_INITIALIZER

int pthread_cond_signal(pthread_cond_t* cond);只确保唤醒至少一条遭到阻塞的线程

int pthread_cond_broadcast(pthread_cond_t* cond);唤醒所有遭到阻塞的线程

int pthread_cond_wait(pthread_cond_t* cond,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_once(pthread_once_t* once_control,void(*init)(void));确保无论调用了多少次,只会执行一次由init指向的函数

 

线程与进程

线程间的数据共享很简单共享相同的地址空间,而进程间的数据共享需要创建共享内存或者使用管道之类的

创建线程要快于创建进程,线程间的上下文切换消耗时间要比进程短

多线程编程需要关注线程安全,多进程不需。

 

线程与exec()

若有任一线程调用exec()函数之一,调用程序将会被完全替换,除了调用的线程外,其余的线程,互斥量,条件变量都会消失。且调用线程在调用exec()之后的线程ID是不确定的。

 

线程与fork()

当多线程进程调用fork(),只会将发起调用的线程复制到子进程中,其他线程均在子进程中消失。全局变量的状态,互斥量,条件变量之类都会在子进程中得以保留。在多线程程序中调用fork()后紧跟着对exec()调用

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值