Linux线程及同步

Linux多线程

1.线程概述
线程是一个进程内的基本调度单位,也可以称为轻量级进程。线程是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。因此,大大减少了上下文切换的开销。一个进程可以有多个线程,也就
是有多个线程控制表及堆栈寄存器,但却共享一个用户地址空间。

2.线程实现

线程创建 pthread_create()

  所需头文件 #include <pthread.h>
函数原型 int pthread_create ((pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg))
thread:线程标识符
attr:线程属性设置
start_routine:线程函数的起始地址
arg:传递给start_routine的参数
函数返回值 成功:0 出错:-1


线程退出pthread_exit();

 所需头文件#include <pthread.h>
函数原型void pthread_exit(void *retval)
函数传入值 retval:pthread_exit()调用者线程的返回值,可由其他函数如pthread_join 来检索获取


等待线程退出并释放资源pthread_join()

  所需头文件#include <pthread.h>
函数原型int pthread_join ((pthread_t th, void **thread_return))
函数传入值
th:等待线程的标识符
thread_return:用户定义的指针,用来存储被等待线程的返回值(不为NULL时)
函数返回值  成功:0  出错:-1


代码举例

  1. #include<pthread.h> 
  2. #include<stdio.h> 
  3. #include<errno.h> 
  4.  
  5. /*线程1*/ 
  6. void thread1() 
  7.     int i=0; 
  8.      
  9.         while(1) 
  10.         { 
  11.      printf("thread1:%d\n",i); 
  12.      if(i>3) 
  13.         pthread_exit(0); 
  14.      i++; 
  15.      sleep(1); 
  16.     } 
  17.  
  18. /*线程2*/ 
  19. void thread2() 
  20.     int i=0; 
  21.      
  22.         while(1) 
  23.         { 
  24.      printf("thread2:%d\n",i); 
  25.      if(i>5) 
  26.         pthread_exit(0); 
  27.      i++; 
  28.      sleep(1); 
  29.     } 
  30.  
  31. int main() 
  32.  pthread_t t1,t2; 
  33.  
  34. /*创建线程*/ 
  35.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  36.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  37.  /*等待线程退出*/ 
  38.  pthread_join(t1,NULL); 
  39.  pthread_join(t2,NULL); 
  40.  return 0; 

3同步与互斥

<1>互斥锁

 互斥锁的操作主要包括以下几个步骤。
· 互斥锁初始化:pthread_mutex_init
· 互斥锁上锁:pthread_mutex_lock
· 互斥锁判断上锁:pthread_mutex_trylock
· 互斥锁接锁:pthread_mutex_unlock
· 消除互斥锁:pthread_mutex_destroy

 

  1. #include<pthread.h> 
  2. #include<stdio.h> 
  3. #include<errno.h> 
  4.  
  5. int i=0;/*共享变量*/ 
  6. pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;/*互斥锁*/ 
  7.  
  8. void thread1() 
  9.     int ret; 
  10.     while(1) 
  11.     { 
  12.          
  13.       
  14.      ret=pthread_mutex_trylock(&mutex);/*判断上锁*/ 
  15.       
  16.      if(ret!=EBUSY) 
  17.         { 
  18.         pthread_mutex_lock(&mutex);/*上锁*/ 
  19.         printf("This is thread1:%d\n",i); 
  20.        i++; 
  21.       pthread_mutex_unlock(&mutex);/*解锁*/ 
  22.      } 
  23.      sleep(1); 
  24.     } 
  25.  
  26. void thread2() 
  27. {int ret; 
  28.     while(1) 
  29.     { 
  30.       
  31.      ret=pthread_mutex_trylock(&mutex); 
  32.      if(ret!=EBUSY) 
  33.         { 
  34.         pthread_mutex_lock(&mutex); 
  35.         printf("This is thread2:%d\n",i); 
  36.        i++; 
  37.       pthread_mutex_unlock(&mutex); 
  38.      } 
  39.      sleep(1); 
  40.     } 
  41. int main() 
  42.  pthread_t t1,t2; 
  43.  pthread_mutex_init(&mutex,NULL); 
  44.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  45.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  46.   
  47.  pthread_join(t1,NULL); 
  48.  pthread_join(t2,NULL); 
  49.   
  50.  pthread_mutex_destroy(&mutex); 
  51.  return 0; 

<2>信号量

未进行同步处理的两个线程

 

  1. #include<pthread.h> 
  2. #include<stdio.h> 
  3. #include<errno.h> 
  4.  
  5. int i=0; 
  6. void thread1() 
  7.      
  8.     while(1) 
  9.     {   
  10.         printf("This is thread1:%d\n",i); 
  11.       i++; 
  12.       sleep(1); 
  13.   } 
  14.  
  15.  
  16. void thread2() 
  17.  
  18.     while(1) 
  19.     {   
  20.         printf("This is thread2:%d\n",i); 
  21.       i++; 
  22.       sleep(1); 
  23.   } 
  24.  
  25. int main() 
  26.  pthread_t t1,t2; 
  27.  
  28.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  29.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  30.   
  31.  pthread_join(t1,NULL); 
  32.  pthread_join(t2,NULL); 
  33.   
  34.  return 0; 

执行结果如下:

This is thread1:0
This is thread2:1
This is thread2:2
This is thread1:3
This is thread2:4
This is thread1:4
This is thread2:6
This is thread1:7
......
可以看出:
1.线程2的执行并非必须在线程1之后,如果要求线程2必须在线程1之后执行,称为同步
2.线程1和线程2可能对共享变量i的同时进行读取,如果要求每次只有一个线程读取i,成为互斥

信号量的使用
· sem_init用于创建一个信号量,并能初始化它的值。
· sem_wait和sem_trywait相当于P操作,它们都能将信号量的值减一,两者的区别在于若信号量小于零时,   sem_wait将会阻塞进程,而sem_trywait则会立即返回。
· sem_post相当于V操作,它将信号量的值加一同时发出信号唤醒等待的进程。
· sem_getvalue用于得到信号量的值。
· sem_destroy用于删除信号量

 

代码

  1. #include<pthread.h> 
  2. #include<stdio.h> 
  3. #include<errno.h> 
  4. #include <semaphore.h> 
  5.  
  6.  
  7. int i=0; 
  8. sem_t sem1,sem2; 
  9.  
  10.  
  11. void thread1() 
  12.      
  13.     while(1) 
  14.     {   
  15.           sem_wait(&sem1); 
  16.         printf("This is thread1:%d\n",i); 
  17.       i++; 
  18.       sleep(3);/*线程1休眠3s,以便观察线程2在输出3s后才会执行*/ 
  19.       sem_post(&sem2); 
  20.        
  21.   } 
  22.  
  23.  
  24. void thread2() 
  25.  
  26.     while(1) 
  27.     {   
  28.         sem_wait(&sem2); 
  29.         printf("This is thread2:%d\n",i); 
  30.       i++; 
  31.       sem_post(&sem1); 
  32.       sleep(1); 
  33.   } 
  34.  
  35. int main() 
  36.  pthread_t t1,t2; 
  37.  
  38.   
  39.  
  40.  sem_init(&sem1,0,1);/*初始化信号量sem1*/ 
  41.  sem_init(&sem2,0,0); 
  42.  
  43.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  44.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  45.   
  46.  pthread_join(t1,NULL); 
  47.  pthread_join(t2,NULL); 
  48.   
  49.  return 0; 

 

 

  1. #include<pthread.h> 
  2. #include<stdio.h> 
  3. #include<errno.h> 
  4. #include <semaphore.h> 
  5.  
  6.  
  7. int i=0; 
  8. sem_t sem; 
  9.  
  10.  
  11. void thread1() 
  12.      
  13.     while(1) 
  14.     {   
  15.           sem_wait(&sem); 
  16.         printf("This is thread1:%d\n",i); 
  17.       i++; 
  18.       sleep(3);/*线程1休眠3s,以便观察线程2在输出3s后才会执行*/ 
  19.       sem_post(&sem); 
  20.        
  21.   } 
  22.  
  23.  
  24. void thread2() 
  25.  
  26.     while(1) 
  27.     {   
  28.         sem_wait(&sem); 
  29.         printf("This is thread2:%d\n",i); 
  30.       i++; 
  31.       sem_post(&sem); 
  32.       sleep(1); 
  33.   } 
  34.  
  35. int main() 
  36.  pthread_t t1,t2; 
  37.  
  38.   
  39.  
  40.  sem_init(&sem,0,1);/*初始化信号量sem*/ 
  41.  
  42.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  43.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  44.   
  45.  pthread_join(t1,NULL); 
  46.  pthread_join(t2,NULL); 
  47.   
  48.  return 0; 

 

A 1 读写锁

~读加锁状态,若试图以读模式加锁,则获得访问权,若试图以写模式加锁,则阻塞

 

  1. int i=0;/*共享变量*/  
  2. pthread_rwlock_t rwlock;/*互斥锁*/  
  3.   
  4. void thread1()  
  5. {   
  6.     while(1)  
  7.     { 
  8.        pthread_rwlock_rdlock(&rwlock);/*读加锁*/  
  9.        printf("This is thread1:%d\n",i);  
  10.        i++;  
  11.        pthread_rwlock_unlock(&rwlock);/*解锁*/  
  12.      sleep(1);  
  13.     }  
  14. }  
  15.   
  16. void thread2()  
  17.     while(1)  
  18.     {  
  19.         pthread_rwlock_rdlock(&rwlock);  
  20.         printf("This is thread2:%d\n",i);  
  21.        i++;  
  22.       pthread_rwlock_unlock(&rwlock);  
  23.       
  24.      sleep(1);  
  25.     }  
  26. }  
  27. int main()  
  28. {  
  29.  pthread_t t1,t2;  
  30.  pthread_rwlock_init(&rwlock,NULL);  /*初始化*/
  31.  pthread_create(&t1,NULL,(void *)thread1,NULL);  
  32.  pthread_create(&t2,NULL,(void *)thread2,NULL);  
  33.    
  34.  pthread_join(t1,NULL);  
  35.  pthread_join(t2,NULL);  
  36.    
  37.  pthread_rwlock_destroy(&rwlock);  /*销毁*/
  38.  return 0;  

结果:

This is thread2:0
This is thread1:0
This is thread2:2
This is thread1:2
This is thread2:4
This is thread1:4
This is thread2:6
This is thread1:6
This is thread2:8
This is thread1:9
可以看到 ,线程1以读模式加锁后,线程2以读模式加锁,未阻塞,可以访问变量i,

当将线程2改为写模式加锁后,结果为:

This is thread2:0
This is thread1:1
This is thread2:2
This is thread1:3
This is thread2:4
This is thread1:5
This is thread1:6
This is thread2:7
This is thread1:8
This is thread2:9
此时,线程2会处于阻塞,直至线程1释放锁。

~写加锁状态,若试图加锁,则线程将阻塞,直至释放锁

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章