什么是线程?
线程就是轻量级的进程
多线程的优点:线程之间除了栈区的内容其他的都是共享的
缺点:互斥与同步
那么,什么时候使用多线程,什么时候使用多进程呢?
1、当创建和销毁较频繁使用线程,因为创建进程的花销比较大
2、需要传输大量数据使用线程,因为多线程切换速度快,不需要跨越进程边界
3、安全稳定选进程,快速频繁选线程
线程相关函数
1、创建线程
#include <pthead.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine(void *),void *arg));
参数一:pthread _t *
参数二:线程的属性,一般设置为NULL
参数三:函数的指针(函数名) void * (void *)
参数四:主线程给子线程通过该参数传值
并且在编译时要连接pthread库 -lpthread
2、等待子线程结束
#include <pthread.h>
int pthread_join(pthread_t thread,void **retval);
参数一:pthread_t
参数二:子线程给主线程传值 NULL
#include <stdio.h>
#include <pthresad.h>
#include <unistd.h>
void *thread(void *arg)
{
while(1)
{
printf("Hello\n");
sleep(1);
}
}
void * thread2(void * arg)
{
while(1)
{
printf("world\n");
sleep(1);
}
}
int main()
{
//创建线程
pthread_t pid1,pid2;
pthread_create(&pid1,NULL,thread1,NULL);
//参数一:pthread_t *
//参数二:线程的属性
//参数三:函数的指针 void *函数名(void *)
//参数四:主线程的子线程的子线程通过该参数传值
pthread_create(&pid2,NULL,thread2,NULL);
//等待线程结束
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
return 0;
}
3、线程退出
(1)主动退出
#include <pthraed.h>
void pthread_exit(void *retval);
参数:NULL,线程结束时不带值
void *thread1(void *arg)
{
int i=0;
while(1)
{
if(5==i)
{
pthread_exit(NULL);//线程主动退出,表示该线程退出不带出来值
}
printf("Hello world\n");
sleep(1);
}
}
(2)被动取消
#include <pthraed.h>
int pthread_cancel(pthread_t thread);
参数:线程的ID号
int i=0;
while(1)
{
if(i>5)
{
pthread_cancel(pid2);//参数:线程的ID号
}
printf("main pthread\n");
sleep(1);
j++;
}
前面提到了线程之间除了栈区其他都是共享的,也就是说全局变量与堆区数据都是共享的,可以通过代码做一个小测试
#include <stdio.h>
#include <prthead.h>
int a=10;
void *pthread1(void *arg)
{
a+=10;
printf("pthread1 a=%d\n",a);
}
void *pthread2(void *arg)
{
a+=20;
printf("pthread a=%d\n",%d);
}
int main()
{
pthraed_t pid1,pid2;
pthread_create(&pid1,NULL,thread1,NULL);
pthread_create(&pid2,NULL,thread2,NULL);
a+=15;
printf("main pthread a=%d\n",a);
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
return 0;
}
通过以上代码就可以得到,
main thread a=25
pthread1 a=35
pthread a=55,由此就可以得出结论
对堆区的数据也可以采用相同的方法验证
线程之间的通信
1、主线程给子线程传值
通过创建线程的第四个参数让主线程给子线程传值
2、子线程给主线程传值
通过exit(),pthread()函数配合使用,通过exit()函数的参数与pthread_join()函数的第二个参数实现子线程给主线程传值
线程中需要解决的问题
1、互斥:多线程不允许同时访问临界资源
互斥锁的作用:互斥锁主要用来保护临界资源
每个临界资源都由一个互斥锁来保护,任何时刻最多只能有一个线程能访问该资源
线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。如果无法获得锁,线程会阻塞直到获得锁为止
互斥锁的相关函数:
初始化互斥锁:
#include <pthread.h>
函数原型:int pthread_mutex_init(pthread_mutex_t * mutex,pthread_muexattr_t * attr)
参数一:mutex :互斥锁
参数二:互斥锁:互斥锁属性//NULL表示缺省属性
返回值:
成功:0
失败:-1
申请互斥锁:
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t * mutex)
参数:mutex:互斥锁
返回值:
成功:0
失败:-1
释放互斥锁:
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t * mutex)
函数参数:mutex:互斥锁
函数返回值:
成功:0
出错:-1
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
char str[20]={'\0'};
//定义一个全局的锁,多线程公用一个互斥锁
pthread_mutex_t mymutex;
void *thread(*arg)
{
char *pc=(char *)arg;
//将主线程传过来的值一个一个赋值
//申请锁
pthread_mutex_lock(&mymutex);
int i=0;
while(*pc)
{
str[i]=*pc;
pc++;
i++;
sleep(1);
printf("%s\n",str);
}
str[i]='\0';
printf("%s\n",str);
//释放锁
ptfread_mutex_unlock(&mymutex);
}
int main()
{
char str1[20]="0123456789";
char str2[20]="abcdefghij";
char str3[20]="ABCDEFGHIJ";
//初始化互斥锁
pthread_mutex_init(&mumutex,NULL);
//创建3个线程
pthread_t pid1,pid2,pid3;
pthread_create(&pid1,NULL,thread,str1);
pthread_create(&pid2,NULL,thread,str2);
pthread_create(&pid3,NULL,thread,str3);
//等待结束
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
pthread_join(pid3,NULL);
}
同步:多线程去访问临界资源时,按照一定的操作顺序来访问。
信号量:
有名信号量:多进程实现同步
无名信号量:多线程同步
信号灯采集:多进程实现同步
信号量的引用:
更新中...