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 |
代码举例
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- /*线程1*/
- void thread1()
- {
- int i=0;
- while(1)
- {
- printf("thread1:%d\n",i);
- if(i>3)
- pthread_exit(0);
- i++;
- sleep(1);
- }
- }
- /*线程2*/
- void thread2()
- {
- int i=0;
- while(1)
- {
- printf("thread2:%d\n",i);
- if(i>5)
- pthread_exit(0);
- i++;
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- /*创建线程*/
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- /*等待线程退出*/
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- return 0;
- }
3同步与互斥
<1>互斥锁
互斥锁的操作主要包括以下几个步骤。
· 互斥锁初始化:pthread_mutex_init
· 互斥锁上锁:pthread_mutex_lock
· 互斥锁判断上锁:pthread_mutex_trylock
· 互斥锁接锁:pthread_mutex_unlock
· 消除互斥锁:pthread_mutex_destroy
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- int i=0;/*共享变量*/
- pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;/*互斥锁*/
- void thread1()
- {
- int ret;
- while(1)
- {
- ret=pthread_mutex_trylock(&mutex);/*判断上锁*/
- if(ret!=EBUSY)
- {
- pthread_mutex_lock(&mutex);/*上锁*/
- printf("This is thread1:%d\n",i);
- i++;
- pthread_mutex_unlock(&mutex);/*解锁*/
- }
- sleep(1);
- }
- }
- void thread2()
- {int ret;
- while(1)
- {
- ret=pthread_mutex_trylock(&mutex);
- if(ret!=EBUSY)
- {
- pthread_mutex_lock(&mutex);
- printf("This is thread2:%d\n",i);
- i++;
- pthread_mutex_unlock(&mutex);
- }
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- pthread_mutex_init(&mutex,NULL);
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- pthread_mutex_destroy(&mutex);
- return 0;
- }
<2>信号量
未进行同步处理的两个线程
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- int i=0;
- void thread1()
- {
- while(1)
- {
- printf("This is thread1:%d\n",i);
- i++;
- sleep(1);
- }
- }
- void thread2()
- {
- while(1)
- {
- printf("This is thread2:%d\n",i);
- i++;
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- 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用于删除信号量
代码
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- #include <semaphore.h>
- int i=0;
- sem_t sem1,sem2;
- void thread1()
- {
- while(1)
- {
- sem_wait(&sem1);
- printf("This is thread1:%d\n",i);
- i++;
- sleep(3);/*线程1休眠3s,以便观察线程2在输出3s后才会执行*/
- sem_post(&sem2);
- }
- }
- void thread2()
- {
- while(1)
- {
- sem_wait(&sem2);
- printf("This is thread2:%d\n",i);
- i++;
- sem_post(&sem1);
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- sem_init(&sem1,0,1);/*初始化信号量sem1*/
- sem_init(&sem2,0,0);
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- return 0;
- }
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- #include <semaphore.h>
- int i=0;
- sem_t sem;
- void thread1()
- {
- while(1)
- {
- sem_wait(&sem);
- printf("This is thread1:%d\n",i);
- i++;
- sleep(3);/*线程1休眠3s,以便观察线程2在输出3s后才会执行*/
- sem_post(&sem);
- }
- }
- void thread2()
- {
- while(1)
- {
- sem_wait(&sem);
- printf("This is thread2:%d\n",i);
- i++;
- sem_post(&sem);
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- sem_init(&sem,0,1);/*初始化信号量sem*/
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- return 0;
- }
A 1 读写锁
~读加锁状态,若试图以读模式加锁,则获得访问权,若试图以写模式加锁,则阻塞
- int i=0;/*共享变量*/
- pthread_rwlock_t rwlock;/*互斥锁*/
- void thread1()
- {
- while(1)
- {
- pthread_rwlock_rdlock(&rwlock);/*读加锁*/
- printf("This is thread1:%d\n",i);
- i++;
- pthread_rwlock_unlock(&rwlock);/*解锁*/
- sleep(1);
- }
- }
- void thread2()
- {
- while(1)
- {
- pthread_rwlock_rdlock(&rwlock);
- printf("This is thread2:%d\n",i);
- i++;
- pthread_rwlock_unlock(&rwlock);
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- pthread_rwlock_init(&rwlock,NULL); /*初始化*/
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- pthread_rwlock_destroy(&rwlock); /*销毁*/
- 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释放锁。
~写加锁状态,若试图加锁,则线程将阻塞,直至释放锁