Unix编程-线程
Posted PorFavor
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unix编程-线程相关的知识,希望对你有一定的参考价值。
线程
进程是一个程序的一个实例,拥有自己独立的各种段(数据段,代码段等等),每次创建一个进程需要从操作系统分配这些资源给他,消耗一定的时间,在linux下C语言创建一个进程使用fork()函数;
线程是一个轻量级的进程,除了自己少数的资源,不用用其他资源,且一个进程可以创建多个线程,这些线程共享进程的资源,创建线程的时间要比创建进程少很多,从函数角度是使用clone()创建。
使用线程处理文件I/O或者socket处理都是非常有优势的,将一个大任务分解成若干个小任务,每个线程处理一个任务,线程之间切换不需要花很多时间,而且线程之间数据交换很方便,共享存储区。
创建线程
int pthread_create(pthread_t * tid, const pthread_attr_t * attr, void * ( * func) (void * ), void * arg);
其返回值是一个整数,若创建进程成功返回0,否则,返回其他错误代码。
pthread_t * tid 线程变量名:pthread_t *类型,是标示线程的id,一般是无符号整形,这里也可以是引用类型,目的是用于返回创建线程的ID
const pthread_attr_t * attr 线程的属性指针:制定线程的属性,比如线程优先*级,初始栈大小等,通常情况使用的都是指针。默认为NULL。
void * ( * func) (void * ) 创建线程的程序代码:一般是函数指针,进程创建后执行该函数指针指向的函数。
void * arg 程序代码的参数:若线程执行的函数包含由若干个参数,需要将这些参数封装成结构体,并传递给它指针。
pthread_t pthread_self (void);
用于返回当前进程的ID
int pthread_equal(pthread_t thread1, pthread_t thread2)
判断两个线程描述符是否指向同一线程。在LinuxThreads中,线程ID相同的线程必然是同一个线程
结束线程
void pthread_exit (void *status);
status: 指针类型,用于存储线程结束后返回状态。
线程等待
int pthread_join (pthread_t tid, void ** thread_return);
pthread_t tid:要等待结束的线程的标识
void **thread_return 指针thread_return指向的位置存放的是终止线程的返回状态。默认为NULL。
pthread_create调用成功以后,新线程和老线程谁先执行,谁后执行用户是不知道的,这一块取决与操作系统对线程的调度。
如果我们需要等待指定线程结束,需要使用pthread_join函数,这个函数实际上类似与多进程编程中的waitpid。
举个例子,以下假设 A 线程调用 pthread_join 试图去操作B线程,该函数将A线程阻塞,直到B线程退出,当B线程退出以后,A线程会收集B线程的返回码。
分离线程
int pthread_detach (pthread_t tid);
pthread_t tid: 指定线程的ID
指定的ID的线程变成分离状态;若指定线程是分离状态,则 如果线程退出,那么它所有的资源都将释放。
对于一个处于分离状态的线程,不可使用pthread_join。
如果线程不是分离状态,线程必须保留它的线程ID、退出状态,直到其他线程对他调用pthread_join()函数
互斥锁
多线程之间可能需要互斥的访问一些全局变量,这就需要互斥地来访问,这些需要共享访问的字段被称作是临界资源,访问临界资源的程序段称作是临界区。
实现线程间的互斥与同步机制的是锁机制。
pthread_mutex_t mutex 锁对象
pthread_mutex_init(&mutex,NULL) 在主线程中初始化锁为解锁状态
pthread_mutex_lock(&mutex): 访问临界区加锁操作
pthread_mutex_unlock(&mutex): 访问临界区解锁操作
例 对全局变量的互斥锁
使用三个线程,求从 1 加到 10000 的值
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int sharei = 0;
void increase_num(void);
// add mutex
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int main()
{
int ret;
pthread_t thread1,thread2,thread3;
ret = pthread_create(&thread1,NULL,(void *)&increase_num,NULL);
ret = pthread_create(&thread2,NULL,(void *)&increase_num,NULL);
ret = pthread_create(&thread3,NULL,(void *)&increase_num,NULL);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
pthread_join(thread3,NULL);
printf("sharei = %d\n",sharei);
return 0;
}
void increase_num(void)
{
long i,tmp;
for(i =0;i<=10000;++i){
// lock
if(pthread_mutex_lock(&mutex) != 0){
perror("pthread_mutex_lock");
exit(EXIT_FAILURE);
}
tmp = sharei;
tmp = tmp + 1;
sharei = tmp;
// unlock
if(pthread_mutex_unlock(&mutex) != 0){
perror("pthread_mutex_unlock");
exit(EXIT_FAILURE);
}
}
}
其实这里的加锁不是对共享变量(全局变量)或者共享内存进行保护,这里的加锁实际上是对临界区的控制,所谓的临界区就是访问临界资源的那一段代码,
这段代码对临界资源进行多种操作,正确的情况是不允许这段代码执行到一半,处理器使用权就被其他线程抢走,
所以这段代码具有原子性,即要么执行,要么不执行,不能执行到一半就被抢走处理权,这样就会造成共享数据被污染。
还有一点,添加锁来控制临界区是有代价的,这个代价表现出来就是时间的额外开销,内部过程是因为要保护现场,会利用一些资源,也需要处理器处理的时间。
条件变量
线程a等待某个条件成立,条件成立,线程a才继续向下执行。线程b的执行使条件成立,条件成立之后唤醒线程a,以继续执行。这个条件就是条件变量,pthread_cond_t 就是条件变量类型。
https://blog.csdn.net/weixin_38239856/article/details/78255767
以上是关于Unix编程-线程的主要内容,如果未能解决你的问题,请参考以下文章