C++服务器(五):pthread多线程编程
2016-03-19 20:24
525 查看
多线程采用pthread库。
考虑到多平台下的实现并不会很容易,还有多线程间的同步等问题,采用一个比较通用的库就好了,这样减少很多工作(其实是我不会使用别的库)
pthread_create
这是POSIX线程库的内容,所以编译的时候要加上:
示例代码:
代码倒是很简单易懂,配合函数说明,看一下就能明白了。
我想说的是,关于
pthread_join
pthread_exit
前者用于退出当前线程,但是其子线程仍然继续运行
后者是一个线程同步函数,一般主线程使用,它会等待join 进去的所有线程结束之后才会执行后续的代码。
看函数原型就可以知道,join 是可以捕获exit 的返回值的。
如果最后没有exit 也没有 join 的话, 那么当线程结束的时候,其子线程也会结束,真是太可怕了。
结构体是:
参考:pthread_create()之前的属性设置
code:
嗯,就是这么简单~
为了避免死锁,条件变量应该和互斥变量一起使用。
当
当
code:
输出:
函数
code:
输出:
之所以会这样是因为read的话,是可以允许多人同时read的,但是write则只能 one by one。
函数
还有其他函数,这里不介绍,移步参考资料。
可以用这个实现生产者消费者模型
参考资料:
c++多线程编程
pthread_create()之前的属性设置
线程--线程基本操作
条件变量pthread_cond_t怎么用
Linux信号量 sem_t简介
(其实是讲信号量的)Linux多线程同步的几种方式
(读写者锁)pthread线程同步机制
考虑到多平台下的实现并不会很容易,还有多线程间的同步等问题,采用一个比较通用的库就好了,这样减少很多工作(其实是我不会使用别的库)
创建一个线程
函数原型:#include <pthread.h> int pthread_create(pthread_t * tidp,const pthread_attr_t * attr,void * (* start_rtn)(void * ),void * args);
pthread_create
这是POSIX线程库的内容,所以编译的时候要加上:
-lpthread
示例代码:
#include<pthread.h> #include<iostream> using namespace std; void* say(void*) { cout<<"hello.."<<endl; } void threadTest() { const int THREAD_NUM = 5; pthread_t tids[THREAD_NUM]; //线程的id for(int i=0;i<THREAD_NUM;++i) { int result = pthread_create(tids+i, nullptr, say, nullptr); if(result != 0) { cout<<"pthread_create error : "<<result<<endl; } } pthread_exit(nullptr);//没有这句的话,当此线程over 的时候,其他线程也over } int main() { threadTest(); }
代码倒是很简单易懂,配合函数说明,看一下就能明白了。
我想说的是,关于
pthread_exit和
pthread_join的区别;
pthread_join
pthread_exit
前者用于退出当前线程,但是其子线程仍然继续运行
后者是一个线程同步函数,一般主线程使用,它会等待join 进去的所有线程结束之后才会执行后续的代码。
看函数原型就可以知道,join 是可以捕获exit 的返回值的。
如果最后没有exit 也没有 join 的话, 那么当线程结束的时候,其子线程也会结束,真是太可怕了。
设置线程的属性
pthread_create 的第二个参数是用来设置线程的属性的,在这之前需要先初始化一下。结构体是:
pthread_attr_init
参考:pthread_create()之前的属性设置
线程同步
互斥锁
函数:pthread_mutex_t //--互斥锁(变量) int pthread_mutex_lock(pthread_mutex_t *mutex); //--加锁 int pthread_mutex_unlock(pthread_mutex_t *mutex); //--解锁 int pthread_mutex_destroy(pthread_mutex_t *mutex); //mutex 指向要销毁的互斥锁的指针
code:
pthread_mutex_t mutex; //互斥锁 int sum = 0; void* say(void*) { pthread_mutex_lock(&mutex); //加锁 sum = sum+2; cout<<sum<<endl; pthread_mutex_unlock(&mutex); //解锁 }
嗯,就是这么简单~
条件变量
函数pthread_cond_t //变量声明 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) //等待信号,同时释放互斥锁 int pthread_cond_wait(pthread_cond_t *cond)//释放信号 int pthread_cond_destroy(pthread_cond_t *cond);//销毁条件变量锁
为了避免死锁,条件变量应该和互斥变量一起使用。
pthread_cond_wait应该在互斥区编写,
pthread_cond_signal可以在互斥区,也可以在互斥区外。
当
pthread_cond_wait的时候,会进入阻塞状态,等待唤醒,同时也会释放互斥锁。只有同时当条件变量被唤醒和得到互斥锁的时候,才会重新运行。
当
pthread_cond_signal的时候,会唤醒另一个线程,但是此时并不会释放互斥锁。
code:
pthread_mutex_t mutex; //互斥锁 pthread_cond_t cond; //条件变量 int sum = 0; //当sum 为奇数时 job1 动, 否则job2动 void* job1(void*) { while(sum<=5) { pthread_mutex_lock(&mutex); if((sum&0x1) == 0) { pthread_cond_wait(&cond, &mutex); //等待job2 来叫叫我,同时释放mutex锁 } cout<<"i am job1,now sum = "<<sum<<endl; ++sum; pthread_mutex_unlock(&mutex); } cout<<"job1 is over"<<endl; } void* job2(void*) { while(sum<=5) { pthread_mutex_lock(&mutex); if((sum&0x1)==1) { pthread_cond_signal(&cond);//唤醒job1 ,但是mutex锁还没有解放 cout<<"i am job2 ,now is your turn--job1"<<endl; } else { cout<<"i am job2,now sum = "<<sum<<endl; ++sum; } pthread_mutex_unlock(&mutex); sleep(1); } cout<<"job2 is over"<<endl; pthread_cond_signal(&cond); }
输出:
i am job2,now sum = 0 i am job2 ,now is your turn--job1 i am job1,now sum = 1 i am job2,now sum = 2 i am job2 ,now is your turn--job1 i am job1,now sum = 3 i am job2,now sum = 4 i am job2 ,now is your turn--job1 i am job1,now sum = 5 job1 is over job2 is over
读写锁
读写锁与mutex类似,不过读写锁允许更高的并行性。mutex只有两种状态(lock & unlock),而读写锁有三种状态读模式下加锁(所有以读模式对它进行加锁的线程都可以得到访问权,写模式访问则会被阻塞),写模式加锁(所有试图访问的都会被阻塞)和无锁。函数
pthread_rwlock_t //变量 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); /* 如果希望读写锁有默认的属性,则分配一个NULL给attr */ int pthread_rwlock_destory(pthread_rwlock_t *rwlock); int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
code:
//读写者模型 pthread_rwlock_t job; void* wantToRead(void* n) { while(true) { cout<<" I want to read"<<endl; pthread_rwlock_rdlock(&job); cout<<" I am reading ,and sum = "<<sum<<endl; pthread_rwlock_unlock(&job); sleep(1); } } void* wantToWrite(void*) { while(true) { cout<<" I want to write"<<endl; pthread_rwlock_wrlock(&job); ++sum; cout<<"end--"<<endl; pthread_rwlock_unlock(&job); sleep(4); } } void threadTest() { const int THREAD_NUM = 6; pthread_t tids[THREAD_NUM]; //线程的id pthread_rwlock_init(&job, nullptr); int i=0; for(;i<THREAD_NUM; ++i) { if(i>=THREAD_NUM-2) pthread_create(tids+i, nullptr, wantToWrite, nullptr); else pthread_create(tids+i, nullptr, wantToRead, nullptr); } pthread_exit(nullptr); }
输出:
I want to read I am reading ,and sum = I want to read0 I want to read I am reading ,and sum = 0 I want to write end-- I am reading ,and sum = 1 I want to write I want to read I am reading ,and sum = 1 end-- I want to read I am reading ,and sum = 2 I want to read I am reading ,and sum = 2 I want to read I am reading ,and sum = I want to read I am reading ,and sum = 22
之所以会这样是因为read的话,是可以允许多人同时read的,但是write则只能 one by one。
信号量
信号量并不是pthread 的(貌似是这样)函数
#include<semaphore.h> sem_t //变量声明 int sem_init(sem_t *sem, int pshared, unsigned int value);//pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值 int sem_wait(sem_t * sem);//给信号量减-1,down 操作,如果信号量 < 0 则阻塞。 int sem_post(sem_t * sem);//给信号量加-1,up 操作,如果信号量 >= 0 则唤醒别的进程
还有其他函数,这里不介绍,移步参考资料。
可以用这个实现生产者消费者模型
//生产者消费者模型 sem_t semMutex; //1 sem_t empty;//n=3 sem_t full;//0 void* producer(void* n) { int i = *(reinterpret_cast<int*>(n)); while(true) { sem_wait(&empty); sem_wait(&semMutex); ++sum; cout<<"producer"<<i<<" is create one, sum = "<<sum<<endl; sem_post(&semMutex); sem_post(&full); sleep(1); } } void* consumer(void* n) { int num = *(reinterpret_cast<int*>(n)); while(true) { sem_wait(&full); sem_wait(&semMutex); --sum; cout<<"consumer"<<num<<" is serviced one, sum = "<<sum<<endl; sem_post(&semMutex); sem_post(&empty); sleep(1); } }
参考资料:
c++多线程编程
pthread_create()之前的属性设置
线程--线程基本操作
条件变量pthread_cond_t怎么用
Linux信号量 sem_t简介
(其实是讲信号量的)Linux多线程同步的几种方式
(读写者锁)pthread线程同步机制