多线程采用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线程同步机制