浅谈一下linux线程
Posted sucfrperperseverance
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈一下linux线程相关的知识,希望对你有一定的参考价值。
1.线程是进程中最小执行单元,多线程共享同一个进程的地址空间
2.Linux 内核调度的对象是线程,所以一个进程中多个线程参与操作操作系统统一调度
使用线程优点:
<1>效率高
<2>线程之间通信比较简单(全局变量)
使用线程缺点:
安全性差
线程API
1.线程创建
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数:
@thread 获取线程ID
@attr 设置线程属性 NULL:默认属性
@start_routine 线程执行的函数
@arg 给线程执行函数传递的参数
返回值:
成功返回0, 失败返回错误码
实例如下:
#include <head.h> void *output(void *arg) { int data = *(int *)arg; printf("%d : %d\\n",pthread_self(),data); return; } int main(int argc, const char *argv[]) { int ret; int count = 0; int data = 0; pthread_t tid; while(1) { /*bug : * 一个线程被创建后,不一定立即运行,而每个线程都是从data的地址中读取数据 *,而data地址的数据又一直在发生变化,这样可能会导致,线程运行的时候,从data地址读取 *的数据已经不是它想要的数据了。 * */ ret = pthread_create(&tid,NULL,output,&data); if(ret != 0){ fprintf(stderr,"Fail to pthread_create : %s\\n",strerror(ret)); exit(EXIT_FAILURE); } i ++; pthread_detach(tid); data ++; count ++; printf("count = %d!\\n",count); // pthread_join(tid,NULL); } return 0; }
运行如下
实例如下
创建两个子线程,子1线程输出data值,子2线程data ++操作,主线程将data -- 操作 (data 在主线程定义)
#include <head.h> void *output_data(void *arg) { int data = *(int *)arg; while(1) { data = *(int *)arg; printf("data = %d!\\n",data); // sleep(1); } } void *add_data(void *arg) { int *pdata = (int *)arg; while(1) { (*pdata) ++; } } int main(int argc, const char *argv[]) { int ret; pthread_t tid1,tid2; int data = 10; ret = pthread_create(&tid1,NULL,output_data,&data); if(ret != 0){ fprintf(stderr,"Fail to pthread_create : %s\\n",strerror(ret)); exit(EXIT_FAILURE); } ret = pthread_create(&tid2,NULL,add_data,&data); if(ret != 0){ fprintf(stderr,"Fail to pthread_create : %s\\n",strerror(ret)); exit(EXIT_FAILURE); } while(1) { data --; } exit(EXIT_SUCCESS); }
运行结果
可见线程的运行并没有先后顺序
2.线程退出
(1)线程函数返回 (return)
(2)pthread_exit
(3)pthread_cancel
(4)进程结束,这个进程中所有的线程都退出
void pthread_exit(void *retval);
功能:用来退出一个线程
参数:
@retval 返回一个地址值
int pthread_join(pthread_t thread, void **retval);
功能:等待一个线程退出,将退出线程未释放的资源释放掉
参数:
@thread 需要等待退出线程的ID
@retval 获得线程退出返回的值
void *thread_function(void *arg)
{
int data = 100;
pthread_exit(&data);
}
int main()
{
int *p;
pthread_join(tid,&p);
return 0;
}
3.将线程标记分离
分离状态的线程在结束的时候,系统自动回收它的资源
int pthread_detach(pthread_t thread);
@thread 线程ID
实例如下:
(1)全局int data[] = {1,2,3,4,5,6,7,8,9,10,11};
(2)线程1一直对全局数组做逆置
(3)线程2一直对全局数组输出
#include <head.h> //pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t lock; int a[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; void *output_array(void *arg) { int i = 0; //实现效果:如果发现逆置操作没有结束,则不输出此时阻塞自己 while(1) { pthread_mutex_lock(&lock); for(i = 0;i < 20;i ++){ printf("%d ",a[i]); } printf("\\n"); pthread_mutex_unlock(&lock); } } void *reverse_array(void *arg) { int t; int i ,j; //实现效果:如果输出操作没有结束,则不逆置阻塞字节 while(1) { pthread_mutex_lock(&lock); i = 0; j = 19; while(i < j){ t = a[i]; a[i] = a[j]; a[j] = t; i ++; j --; } pthread_mutex_unlock(&lock); } } int main(int argc, const char *argv[]) { int ret; pthread_t tid1,tid2; int data = 10; ret = pthread_mutex_init(&lock,NULL); if(ret != 0){ fprintf(stderr,"Fail to pthread_mutex_init"); exit(EXIT_FAILURE); } ret = pthread_create(&tid1,NULL,output_array,NULL); if(ret != 0){ fprintf(stderr,"Fail to pthread_create : %s\\n",strerror(ret)); exit(EXIT_FAILURE); } ret = pthread_create(&tid2,NULL,reverse_array,NULL); if(ret != 0){ fprintf(stderr,"Fail to pthread_create : %s\\n",strerror(ret)); exit(EXIT_FAILURE); } pthread_join(tid1,NULL); exit(EXIT_SUCCESS); }
运行结果
并没有出现还没有逆置完成就输出的
但如果去掉
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
呢?
线程互斥锁
功能:对共享资源实现互斥访问,保证访问的完整性
如果使用互斥锁,每个线程在访问共享资源,都必须先获得互斥锁,然后在访问共享资源,如果无法获得互斥锁
,则表示有其他线程正在访问共享资源,此时没有获得锁的线程会阻塞,直到其他线程释放锁,能再次获得锁
1.定义互斥锁[全局,让每个线程都可以访问到]
pthread_mutex_t lock;
2.初始化互斥锁
//[线程创建之前]动态初始化,属性使用默认 NULL
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
//静态初始化定义初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
3.获得互斥锁
int pthread_mutex_lock(pthread_mutex_t *mutex);//操作共享资源之前加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
4.释放锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);//操作共享资源结束的时候
5.销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);//不需要再次使用锁的时候
线程间同步
同步:相互之间配合完成一件事情
互斥:保证访问共享资源的完整性(有你没我)
POSIX 线程中同步:使用信号量实现
信号量 : 表示一类资源,它的值表示资源的个数
对资源访问:
p操作(申请资源) [将资源的值 - 1]
....
V操作(释放资源) [将资源的值 + 1]
1.定义信号量
sem_t sem ;
2.初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
@sem 信号量
@pshared 0:线程间使用
@value 初始化的信号量的值
返回值:
成功返回0,失败返回-1
3.P操作
int sem_wait(sem_t *sem);
4.V操作
int sem_post(sem_t *sem);
实例如下:
创建两个线程
write_thread : 从键盘上读取用户输入的数据,写到文件中
read_thread : 从文件中读取数据,然后输出
main_thread : 打开一个文件
#include <head.h> sem_t read_sem;//读资源 sem_t write_sem;//写资源 void *write_thread(void *arg) { char buf[1024]; int fd = *(int *)arg; while(1){ //申请写资源 if(sem_wait(&write_sem) < 0){ perror("Fail to sem_wait"); pthread_exit(NULL); } fgets(buf,sizeof(buf),stdin); buf[strlen(buf) - 1] = \'\\0\'; write(fd,buf,strlen(buf)); //还原偏移量到上一次值 lseek(fd,-strlen(buf),SEEK_CUR); //释放读资源 if(sem_post(&read_sem) < 0){ perror("Fail to sem_wait"); pthread_exit(NULL); } if(strcmp(buf,"quit") == 0){ break; } } pthread_exit(NULL); } void *read_thread(void *arg) { int n; char buf[1024]; int fd = *(int *)arg; while(1){ //申请读资源 if(sem_wait(&read_sem) < 0){ perror("Fail to sem_wait"); pthread_exit(NULL); } n = read(fd,buf,sizeof(buf)); buf[n] = \'\\0\'; printf("Read %d bytes : %s!\\n",n,buf); //释放写资源 if(sem_post(&write_sem) < 0){ perror("Fail to sem_wait"); pthread_exit(NULL); } if(strcmp(buf,"quit") == 0){ break; } } pthread_exit(NULL); } //./a.out file int main(int argc, const char *argv[]) { int fd; int ret; pthread_t rtid; pthread_t wtid; if(argc < 2){ fprintf(stderr,"Usage : %s <filename>!\\n",argv[0]); exit(EXIT_FAILURE); } fd = open(argv[1],O_RDWR | O_CREAT | O_TRUNC,0666); if(fd < 0){ fprintf(stderr,"Fail to open %s : %s\\n",argv[1],strerror(errno)); exit(EXIT_FAILURE); } if(sem_init(&read_sem,0,0) < 0){ perror("Fail to sem_init"); exit(EXIT_FAILURE); } if(sem_init(&write_sem,0,1) < 0){ perror("Fail to sem_init"); exit(EXIT_FAILURE); } ret = pthread_create(&rtid,NULL,read_thread,&fd); if(ret != 0){ fprintf(stderr,"Fail to pthread_create : %s!\\n",strerror(ret)); exit(EXIT_FAILURE); } ret = pthread_create(&wtid,NULL,write_thread,&fd); if(ret != 0){ fprintf(stderr,"Fail to pthread_create : %s!\\n",strerror(ret)); exit(EXIT_FAILURE); } pthread_join(rtid,NULL); pthread_join(wtid,NULL); return 0; }
以上是关于浅谈一下linux线程的主要内容,如果未能解决你的问题,请参考以下文章