(1)线程是任务调度和执行的基本单位。
(2)为什么会有线程?
A-进程实现多任务的缺点:
a.进程间切换的计算机资源开销很大,切换效率非常低。
b.进程间数据共享的开销也很大。
B-线程和进程的关系
1.线程是进程的一个执行单元,是进程内的调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程
2.同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间
3.进程退出,进程中所有线程全部退出
4.一个进程崩溃后,不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮
5.线程不可能完全替代进程
6.线程拥有独立的属性:独立的ID(TID),独立的切换状态,调度优先级,独立函数栈等等
(3)线程的特点:
①线程切换的开销很低(实质是函数的切换);
②线程通信机制简单(全局变量)。
——注意:线程函数不是OS提供,而是线程库而是线程库libpthread.a/.so,但是线程的核心实现是离不开OS支持的
①线程控制函数有: pthread_create、pthread_join、pthread_detach、pthread_cancel、pthread_ exit等。
②线程库和函数手册的安装:
sudo apt-get install glibc-doc
安装线程库
sudo apt get install manpages posix dev: 安装线程库的函数手册
③线程创建 :
代码实例:创建两个次线程,主线程和两个次线程一起的向同一个文件中写"hello”“world\n”
API:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
#include
#include
#include
voi * thread1(void *arg)
{
while(1)
{
printf("hello world!\n");
sleep(1);
}
}
int main()
{
pthread_t id;
if(pthread_create(&id,NULL,thread1,NULL)!=0)
{
perror("pthread create error!\n")
exit(1);
}
pause();
return 0;
}
④线程退出:
被动退出
API:int pthread_cancel(pthread_t thread);
必须要有系统调用
主动退出
int pthread_exit(void *retval); 弹栈
如果返回值很多时,就封装成一个结构体,返回结构体变量的地址即可。
return 返回 ;不弹栈
⑤线程等待:
等待线程的目的:
每个可结合线程需要显示的调用pthread_join回收
将其变成分离态的线程;线程分离函数–pthread_ detach
线程VS进程
进程:进程空间天然是独立的,因此进程间资源的保护是天然的(现成的),需要重点关心的进程间的通信
线程:多线程天然的共享进程空间,因此线程数据共享是天然的(现成的),需要重点关心的是资源的保护
互斥锁——必须设置为全局变量
定义一个互斥锁(pthread_mutex_t mutex)
初始化互斥锁(pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER)
加锁解锁(阻塞加锁,非阻塞加锁,访问临界区解锁)
进程退出时销毁互斥锁(删除互斥锁相关的数据,释放互斥锁数据所占用的各种内存资源。)
线程信号量
定义信号量结合(sem_t sem[n],线程信号量集合其实就是一个数组,数组每个元素就是一个信号量。)
初始化集合中的每个信号量,int sem_init(sem_t *sem, int pshared, unsigned int value);
p、v操作( int sem_wait(sem_t *sem)//阻塞p操作;int sem_post(sem_t *sem))
进程结束时,删除线程信号量集合( int sem_destroy(sem_t *sem);)
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct message
{
int fd;
};
sem_t sem[1];
void * thread1(void *arg)
{
struct message msg = *((struct message * )arg);
int fd= msg.fd;
while(1)
{
sem_wait(&sem[0]);
write(fd,"111\n",4);
sem_post(&sem[0]);
}
}
void * thread2(void *arg)
{
struct message msg = *((struct message * )arg);
int fd= msg.fd;
while(1)
{
sem_wait(&sem[0]);
write(fd,"222\n",4);
sem_post(&sem[0]);
}
}
void *thread3(void *arg)
{
struct message msg = *((struct message * )arg);
int fd= msg.fd;
while(1)
{
sem_wait(&sem[0]);
write(fd,"333\n",4);
sem_post(&sem[0]);
}
}
int main()
{
pthread_t id1;
pthread_t id2;
pthread_t id3;
struct message msg;
int fd;
fd=open("./a.txt",O_RDWR | O_CREAT | O_APPEND,0644);
if(fd<0)
{
perror("open file error!");
exit(1);
}
msg.fd=fd;
sem_init(&sem[0],0,1);
if(pthread_create(&id1,NULL,thread1,(void *)(&msg)) != 0)
{
perror("thread create error!\n");
exit(1);
}
if(pthread_create(&id2,NULL,thread2,(void *)(&msg)) != 0)
{
perror("thread create error!\n");
exit(1);
}
if(pthread_create(&id3,NULL,thread3,(void *)(&msg)) != 0)
{
perror("thread create error!\n");
exit(1);
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_join(id3,NULL);
return 0;
}
条件变量
多线程配合工作时,当线程检测到某条件不满足时就休眠,直到别的线程将条件准备好,然后通过条件变量将其唤醒。
条件变量需要在互斥锁的配合下才能工作
定义一个条件变量(全局变量)由于条件变量需要互斥锁的配合,所以还需要定义一个线程互斥锁(pthread_cond_t)
初始化条件变量(int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);)
使用条件变量( int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); )
删除条件变量,也需要把互斥锁删除(int pthread_cond_destroy(pthread_cond_t *cond);)
#include
#include
#include
int count = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void * add_1(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
count++;
if(count == 5)
{
pthread_cond_signal(&cond);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
void * print_1(void * arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(count!=5)
{
pthread_cond_wait(&cond,&mutex);
}
printf("count = %d\n",count);
count =0;
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
pthread_t id1;
pthread_t id2;
int ret;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
ret=pthread_create(&id1,NULL,add_1,NULL);
if(ret!=0)
{
perror("thread creare error!");
exit(1);
}
ret=pthread_create(&id2,NULL,print_1,NULL);
if(ret!=0)
{
perror("thread creare error!");
exit(1);
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
return 0;
}