1.进程与线程的区别
答:一个程序的运行叫做进程,线程是进程的容器。一个进程在运行时,系统会给他分配内存,维护他的数据段,代码段、堆、栈等等,而线程会共享进程这些资源。
一个进程同一时刻只做一件事,有了线程后,可以把进程设计成在同一时刻做多件事。
进程有独立的地址空间,进程崩溃后,不会对其他进程造成影响。线程没有独立的地址空间,线程死掉就等于进程死掉。
进程切换时,消耗资源大,效率差。
2.为什么要使用线程
线程是“节俭”的多任务操作模式:从开销方面来讲,线程的开销比较节省。每个线程的切换速度比较快。
线程的通信很方便。对于不同进程来讲,它们有独立的数据空间,要进行数据传递只能通过通信的方式如管道,消息队列,共享内存等等。线程共享的是数据空间,一个线程的数据可以给其他线程使用,这比较方便快捷。
3.线程
(1)线程创建
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// 返回:若成功返回0,否则返回错误编号
当pthread_create成功返回时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,暂可以把它设置为NULL,以创建默认属性的线程。
新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg。如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
(2)线程退出
#include <pthread.h>
int pthread_exit(void *rval_ptr);
rval_ptr是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。
(3)线程等待
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号
如果对线程的返回值不感兴趣,可以把rval_ptr置为NULL。在这种情况下,调用pthread_join函数将等待指定的线程终止,但并不获得线程的终止状态。
(4)线程ID获取
#include <pthread.h>
pthread_t pthread_self(void);
// 返回:调用线程的ID
例子1
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
ret=pthread_create(&t1,NULL,func1,(void *)¶m);
if(ret==0){
printf("pthread creat ok\n");
}
printf("main:%ld \n",(unsigned long)pthread_self());
//pthread_self()获取线程ID
//while(1);
pthread_join(t1,NULL);
return 0;
}
运行结果:
pthread creat ok
main:140192978982656
t1:140192970696448 thread is create
param is 100
例子2
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{
static int ret = 10 ;
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
pthread_exit((void *)&ret);
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
int *pret;
ret=pthread_create(&t1,NULL,func1,(void *)¶m);
if(ret==0){
printf("pthread creat ok\n");
}
printf("main:%ld \n",(unsigned long)pthread_self());
pthread_join(t1,(void **)&pret);
printf("main:ti quit %d \n",*pret);
return 0;
}
例子2实现了主线程等待时实现接收线程返回的值。
结果:
pthread creat ok
main:140672702207744
t1:140672693921536 thread is create
param is 100
main:ti quit 10
例子3
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{
static char *p="t1 run";
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
pthread_exit((void *)p);
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
char *pret;
ret=pthread_create(&t1,NULL,func1,(void *)¶m);
if(ret==0){
printf("pthread creat ok\n");
}
printf("main:%ld \n",(unsigned long)pthread_self());
// while(1);
pthread_join(t1,(void **)&pret);
printf("main:ti quit %s \n",pret);
return 0;
}
当然返回字符串也可以
结果:
pthread creat ok
main:140689130268416
t1:140689121982208 thread is create
param is 100
main:ti quit t1 run
例子4
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;
void *func1(void *arg)
{
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
while(1){
printf("t1:%d\n",g_data++);
sleep(1);
if(g_data==7){
pthread_exit(NULL);
}
}
}
void *func2(void *arg)
{
printf("t2::%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
while(1){
printf("t2:%d\n",g_data++);
sleep(1);
}
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
pthread_t t2;
ret=pthread_create(&t1,NULL,func1,(void *)¶m);
ret=pthread_create(&t2,NULL,func2,(void *)¶m);
if(ret==0){
printf("pthread creat ok\n");
}
printf("main:%ld \n",(unsigned long)pthread_self());
while(1){
printf("main:%d\n",g_data++);
sleep(1);
}
pthread_join(t1,NULL);
pthread_join(t2,NULL);
return 0;
}
两个线程验证同一进程下, 同一时刻做不止一件事,每个线程各自处理独立的任务。
结果:
4.互斥锁
(1)创建及销毁互斥锁
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
// 返回:若成功返回0,否则返回错误编号
要用默认的属性初始化互斥量,只需把attr设置为NULL。
(2) 加锁及解锁
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
// 返回:若成功返回0,否则返回错误编号
例子5
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex;
void *func1(void *arg)
{
int i;
pthread_mutex_lock(&mutex);
for(i=0;i<5;i++){
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
sleep(1);
}
pthread_mutex_unlock(&mutex);
}
void *func2(void *arg)
{
pthread_mutex_lock(&mutex);
printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
pthread_mutex_unlock(&mutex);
}
void *func3(void *arg)
{
pthread_mutex_lock(&mutex);
printf("t3:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
pthread_mutex_unlock(&mutex);
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
pthread_t t2;
pthread_t t3;
pthread_mutex_init(&mutex,NULL);
ret=pthread_create(&t1,NULL,func1,(void *)¶m);
ret=pthread_create(&t2,NULL,func2,(void *)¶m);
ret=pthread_create(&t3,NULL,func3,(void *)¶m);
if(ret==0){
printf("pthread creat ok\n");
}
printf("main:%ld \n",(unsigned long)pthread_self());
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_join(t3,NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
该代码为互斥锁的实现,哪个线程先运行是随机的,假如func1先运行,那么锁住的代码会先执行完毕才会执行其他线程代码。
例子6
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;
pthread_mutex_t mutex;
void *func1(void *arg)
{
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
pthread_mutex_lock(&mutex);
while(1){
printf("t1:%d\n",g_data++);
sleep(1);
if(g_data==3){
pthread_mutex_unlock(&mutex);
printf("====================\n");
// pthread_exit(NULL);
exit(0);
}
}
}
void *func2(void *arg)
{
printf("t2::%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
while(1){
printf("t2:%d\n",g_data);
pthread_mutex_lock(&mutex);
g_data++;
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
pthread_t t2;
pthread_mutex_init(&mutex,NULL);
ret=pthread_create(&t1,NULL,func1,(void *)¶m);
ret=pthread_create(&t2,NULL,func2,(void *)¶m);
if(ret==0){
printf("pthread creat ok\n");
}
printf("main:%ld \n",(unsigned long)pthread_self());
while(1){
printf("main:%d\n",g_data);
sleep(1);
}
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_mutex_destroy(&mutex);
通过锁的方式验证线程退出而导致进程退出。
结果:
例子7
#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
void *func1(void *arg)
{
int i;
pthread_mutex_lock(&mutex);
sleep(1);
pthread_mutex_lock(&mutex2);
for(i=0;i<5;i++){
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
sleep(1);
}
pthread_mutex_unlock(&mutex);
}
void *func2(void *arg)
{
pthread_mutex_lock(&mutex2);
sleep(1);
pthread_mutex_lock(&mutex);
printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
pthread_mutex_unlock(&mutex);
}
void *func3(void *arg)
{
pthread_mutex_lock(&mutex);
printf("t3:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
pthread_mutex_unlock(&mutex);
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
pthread_t t2;
pthread_t t3;
pthread_mutex_init(&mutex,NULL);
pthread_mutex_init(&mutex2,NULL);
ret=pthread_create(&t1,NULL,func1,(void *)¶m);
ret=pthread_create(&t2,NULL,func2,(void *)¶m);
ret=pthread_create(&t3,NULL,func3,(void *)¶m);
if(ret==0){
printf("pthread creat ok\n");
}
printf("main:%ld \n",(unsigned long)pthread_self());
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_join(t3,NULL);
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex2);
return 0;
}
死锁代码。死锁的意思是两把锁,线程A握着第一把锁想去拿第二把锁,线程B握着第二把锁想去拿第一把锁,谁也不让谁,导致程序阻塞。
结果:
5.与条件变量相关API
(1)创建及销毁条件变量
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
// 返回:若成功返回0,否则返回错误编号
除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。
(2)等待
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
// 返回:若成功返回0,否则返回错误编号
pthread_cond_wait等待条件变为真。如果在给定的时间内条件不能满足,那么会一直阻塞等待。
(3)触发
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
// 返回:若成功返回0,否则返回错误编号
这两个函数可以用于通知线程条件已经满足。pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast函数将唤醒等待该条件的所有进程。
注意一定要在改变条件状态以后再给线程发信号。
例子8
#include <stdio.h>
#include <pthread.h>
int g_data=0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *func1(void *arg)
{
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
while(1){
pthread_cond_wait(&cond,&mutex);
printf("====================\n");
printf("t1:%d\n",g_data++);
g_data=0;
sleep(1);
}
}
void *func2(void *arg)
{
printf("t2::%ld thread is create\n",(unsigned long)pthread_self());
printf("param is %d\n",*(int *)arg);
while(1){
printf("t2:%d\n",g_data);
pthread_mutex_lock(&mutex);
g_data++;
if(g_data==3){
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
int ret;
int param = 100;
pthread_t t1;
pthread_t t2;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
ret=pthread_create(&t1,NULL,func1,(void *)¶m);
ret=pthread_create(&t2,NULL,func2,(void *)¶m);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
该代码利用条件变量等待func2的data==3时,执行pthread_cond_signal语句,func1的pthread_cond_wait才能执行下去。
结果:
参考:linux多线程初探
学习笔记,仅供参考