多线程
创建线程
int pthread_create(pthread_t *restrict __newthread, const pthread_attr_t *restrict __attr, void (__start_routine)(void *), void *restrict __arg)
参数分别为,线程号,状态,回调函数,回调函数的参数
pthread_create(&threadId1, NULL, handleThread1, &num1)
回调函数
void *handleThread1(void *arg)
{
/*线程分离*/
pthread_detach(pthread_self());
int num = *(int *)arg;
int num = 1;
while(1)
{
printf("num=%d\n", num);
num+=2;
/*休眠两秒*/
sleep(2);
}
/*线程退出*/
pthread_exit(NULL);
}
线程分离
防在线程回调函数第一句
/*线程分离:线程结束后系统自动回收*/
pthread_detach(pthread_self());
pthread_self(),返回线程号
通过状态来分离线程
/*初始化线程状态*/
pthread_attr_t threadAttr;
pthread_attr_init(&threadAttr);
/*设置线程分离状态*/
int ret=pthread_attr_setdetachstate(&threadAttr,PTHREAD_CREATE_DETACHED);
if(ret!=0)
{
perror("phtread_attr_setdetachstate:");
/*退出线程*/
_exit(-1);
}
pthread_t threadId;
ret=pthread_create(&threadId, &threadAttr, thread_func, NULL);
if(ret!=0)
{
perror("phtread_create:");
/*退出线程*/
_exit(-1);
}
/*释放线程属性*/
pthread_attr_destroy(&threadAttr);
线程回收
/*一旦线程已经被分离,pthread_join就不能回收他的资源,该线程结束后自动回收*/
pthread_join(threadId1, NULL);
线程退出
/*线程退出*/
pthread_exit(NULL);
线程取消
pthread_cancel(threadId);
函数的形参
传入参数:不可修改
如果是字符串加上const属性
如果是整型,值传递
传出参数:可修改的
锁
互斥锁(互斥量)
一种简单的加锁方式,来控制对共享资源的访问,两种状态,加锁(lock),解锁(unlock)
互斥锁的数据类型:pthread_mutex_t
pthread_mutex_init()函数
int pthread_mutex_init(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr)
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);
pthread_mutex_lock()函数
pthread_mutex_unlock()函数
pthread_mutex_destroy()函数
/*全局变量*/
pthread_mutex_t mutex;
void painter(const char* str)
{
if(str==NULL)
{
return;
}
while(*str!='\0')
{
cout << *str ;
fflush(stdout);
sleep(1);
str++;
}
cout << endl;
return;
}
void* threadFunc1(void* arg)
{
const char *str1 = "hello";
/*加锁*/
pthread_mutex_lock(&mutex);
painter(str1);
/*解锁*/
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void* threadFunc2(void* arg)
{
const char *str2 = "world";
/*加锁*/
pthread_mutex_lock(&mutex);
painter(str2);
/*解锁*/
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main()
{
/*初始化一把锁*/
pthread_mutex_init(&mutex,NULL);
pthread_t threadId1;
int ret=pthread_create(&threadId1, NULL, threadFunc1, NULL);
if(ret!=0)
{
perror("create:");
_exit(-1);
}
pthread_t threadId2;
ret=pthread_create(&threadId2, NULL, threadFunc2, NULL);
if(ret!=0)
{
perror("create:");
_exit(-1);
}
pthread_join(threadId1,NULL);
pthread_join(threadId2,NULL);
/*释放锁*/
pthread_mutex_destroy(&mutex);
return 0;
}
解决死锁:
1、检测到当前程序死锁
(1)内核态阻塞
(2)用户态阻塞(死循环&进程占用的cpu较高)
2、所有的程序的加锁方式必须按照顺序
所有程序的解锁方式也必须按照顺序
读写锁
pthread_rwlock_init函数
pthread_rwlock_destroy函数
pthread_rwlock_rdlock函数
pthread_rwlock_wrlock函数 //写锁,其他线程不允许读或写操作(即拿不到写锁,也拿不到读锁)
pthread_rwlock_unlock函数
#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
pthread_rwlock_t rwlock;
int g_num = 100;
void *threadFunc1(void *arg)
{
// while(1)
// {
pthread_rwlock_rdlock(&rwlock);
for (int i = 0; i < 10;i++)
{
cout << "threadFunc1:" << g_num << endl;
usleep(100);
}
pthread_rwlock_unlock(&rwlock);
// }
pthread_exit(NULL);
}
void* threadFunc2(void* arg)
{
// while(1)
// {
pthread_rwlock_rdlock(&rwlock);
for (int i = 0; i < 10;i++)
{
cout << "threadFunc2:" << g_num << endl;
usleep(100);
}
pthread_rwlock_unlock(&rwlock);
// }
pthread_exit(NULL);
}
void* threadFunc3(void* arg)
{
pthread_rwlock_wrlock(&rwlock);
sleep(10);
g_num++;
pthread_rwlock_unlock(&rwlock);
pthread_exit(NULL);
}
void* threadFunc4(void* arg)
{
pthread_rwlock_wrlock(&rwlock);
sleep(10);
g_num++;
pthread_rwlock_unlock(&rwlock);
pthread_exit(NULL);
}
int main()
{
//初始化读写锁
pthread_rwlock_init(&rwlock, NULL);
pthread_t threadId1;
int ret=pthread_create(&threadId1, NULL, threadFunc1, NULL);
if(ret!=0)
{
perror("create:");
_exit(-1);
}
pthread_t threadId2;
ret=pthread_create(&threadId2, NULL, threadFunc2, NULL);
if(ret!=0)
{
perror("create:");
_exit(-1);
}
pthread_t threadId3;
ret=pthread_create(&threadId3, NULL, threadFunc3, NULL);
if(ret!=0)
{
perror("create:");
_exit(-1);
}
pthread_t threadId4;
ret=pthread_create(&threadId4, NULL, threadFunc4, NULL);
if(ret!=0)
{
perror("create:");
_exit(-1);
}
pthread_join(threadId1,NULL);
pthread_join(threadId2,NULL);
pthread_join(threadId3,NULL);
pthread_join(threadId4,NULL);
//释放读写锁
pthread_rwlock_destroy(&rwlock);
return 0;
}
条件变量
条件变量本身不是锁,用来阻塞一个线程,直到某特殊情况发生,通常条件变量和互斥锁同时使用
条件变量类型:pthread_cond_t
pthread_cond_init函数
pthread_cond_destroy函数
pthread_cond_singal函数
pthread_cond_wait函数:该函数在使用时会自动解锁
pthread_mutex_lock(&g_mutex);
while(g_head==NULL)
{
pthread_cond_wait(&g_cond, &g_mutex);//解锁并等待条件变量被满足 -> pthread_cond_singal()发信号
//当条件被满足时(接受到条件变量),解除阻塞,并重新上锁
}
信号量
类型:sem_t
当信号量大于0时,有访问权限
p操作:一次p操作使信号量-1,v操作:一次v操作使信号量+1
sem_init函数
sem_destroy函数
sem_wait函数加锁 p操作
sem_post函数解锁 v操作
信号量p操作(-1)=加锁
信号量v操作(+1)=解锁
sem_getvalue函数,获得信号量的值
sem占用资源较少
一般使用互斥锁+条件变量,sem的使用场景相对较少