目录
线程中不能使用return
一、进程与线程
- 线程的概念:
- 线程是进程中的一条执行流,是CPU调度的最小单元,一个进程里最少有一个线程
- 线程与进程的区别
- 进程为资源分配的最小单元,线程为执行的最小单位
- 进程具有自己独立的内存空间,当一个进程崩溃时,由于是独立的内存空间,所以不会影响其他进程的运行。线程是在进程内运行的,一个进程可以拥有多个线程,且进程是资源分配的最小单元,所以当进程崩溃或者线程崩溃,那么其他共用一个进程的线程就会崩溃。
- 进程之间的切换开销较大,线程之间的切换开销较小
- 同一个进程内可以拥有多个线程,一个线程只能存在于一个进程之中
- 进程通信通过:管道、消息队列、信号、共享内存等等。线程之间的通信通过全局数据、函数传参。
- 线程优点:
- 占用资源少,创建进程比创建线程的代价大
- 线程切换开销小
- 线程之间的通信更加灵活
- 线程缺点:
- 在变成难度上较高
- 可能会有较大的性能损耗,这里的损耗指,如果计算密集型线程的数量比可用的处理器多,那么就会增加了额外的同步和调度开销,而可用的资源不变。
- 缺乏访问控制
- 线程之间缺乏保护
二、线程开发
- 函数介绍:
函数名 | 作用 |
---|---|
pthread_create | 创建线程,成功返回0 |
pthread_exit | 线程退出,成功返回0 |
pthread_join | 线程等待,调用该函数的将会一直阻塞,知道该进程标识符所对应的进程通过pthread_exit退出或者运行结束 |
pthread_detach | pthread_detach函数把指定的线程转变为脱离状态。 参数为所对应线程的ID |
pthread_self | 线程ID的获取,该函数为在线程内需要获取ID时的函数 该函数没有参数。 |
pthread_equal | 对线程ID进行比较。该函数的参数分别为两个所比较线程的ID。 |
- 函数参数介绍
- pthread_create:
- 第一个参数为线程ID
- 第二个为定制不同的线程属性,暂时设为NULL
- 第三个为:返回值为void*且参数为void*的函数指针
- 第四个为第三个参数所对应函数的参数
- pthread_exit:
- 参数为传递给pthread_join的退出码,该参数为一级指针,该退出码需要使用static关键字或者全局变量。
- pthread_join:
- 第一个参数为等待退出的线程ID
- 第二个参数为接收对应线程退出所发送的退出码,为二级指针,如果不在意退出码的话可以设置为NULL
- pthread_create:
- 实战
#include <stdio.h> #include <pthread.h> //int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); void* thread1(void *arg) { static char *ret = "thread1 quit success!\n"; printf("thread:%ld\n",(unsigned long)pthread_self()); printf("param = %d\n",*((int *)arg)); pthread_exit((void*)ret); } int main() { pthread_t t1; int param = 100; char *pret; if(pthread_create(&t1,NULL,thread1,(void *)¶m) < 0){ printf("thread create error\n"); } printf("main:%ld\n",(unsigned long)pthread_self()); pthread_join(t1,(void **)&pret); printf("thread quit:%s\n",pret); return 0; }
三、线程同步
-
互斥锁:
- 当我们有多个线程对一个变量进行操作时,如果恰巧有多个线程同时进行操作,那么该变量得数值就不会如我们想象的样子进行变化了。此时我们需要对操作该变量的线程进行限制,此时就用到了互斥锁来对变量进行同步,当我们对变量进行操作时,先进行上锁,后进行操作变量,当操作完后进行解锁。(对于在单个cpu上进行的多个线程来说,当我们线程解锁完后,需要进行短暂的延迟,来让其他线程对cpu进行竞争)
- 函数介绍
函数名称 函数作用 pthread_mutex_init
进行创建互斥锁 pthread_mutex_destroy
销毁互斥锁 pthread_mutex_lock
上锁 pthread_mutex_unlock
解锁 -
函数参数
-
pthread_mutex_init
-
第一个参数为互斥变量,用pthread_mutex_t数据类型表示。在使用互斥变量前必须对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量)
-
第二个参数为互斥锁的属性,暂时设做NULL
-
-
pthread_mutex_destroy:参数为互斥变量
-
pthread_mutex_lock和pthread_mutex_unlock:参数都为互斥变量
-
-
实战
include <stdio.h> #include <pthread.h> #include <unistd.h> //int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); int g_data = 0; pthread_mutex_t mutex; void* thread1(void *arg) { int i = 0; pthread_mutex_lock(&mutex); while(1){ printf("t1:%ld\n",(unsigned long)pthread_self()); sleep(1); if(i > 5){ break; } i++; } printf("te quit======================\n"); pthread_mutex_unlock(&mutex); } void* thread2() { while(1){ pthread_mutex_lock(&mutex); printf("t2:%ld\n",(unsigned long)pthread_self()); pthread_mutex_unlock(&mutex); sleep(1); } } int main() { pthread_t t1; pthread_t t2; int param = 100; printf("main:%ld\n",(unsigned long)pthread_self()); pthread_mutex_init(&mutex,NULL); if(pthread_create(&t1,NULL,thread1,(void *)¶m) < 0){ printf("thread1 create error\n"); } if(pthread_create(&t2,NULL,thread2,NULL) < 0){ printf("thread2 create error"); } printf("main: %d\n",g_data++); pthread_join(t1,NULL); pthread_join(t2,NULL); pthread_mutex_destroy(&mutex); return 0; }
- 函数介绍
-
条件变量:
-
条件变量是另一种同步机制,条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量,其他线程在获得互斥量之前不会察觉到这种改变,因为必须锁定互斥量以后才能计算条件。
- 函数介绍
函数名称 函数作用 pthread_cond_init
创建条件变量 pthread_cond_destroy
销毁条件变量 pthread_cond_wait
使用该函数的线程阻塞,条件满足使用pthread_cond_signal或pthread_cond_broadcast唤醒 pthread_cond_signal
pthread_cond_signal函数将唤醒等待该条件的某个线程 pthread_cond_broadcast
pthread_cond_broadcast函数将唤醒等待该条件的所有进程 -
函数参数
-
pthread_cond_init:
-
第一个参数为条件变量
-
第二个参数为属性,设置为默认属性的话为NULL
-
-
pthread_cond_destroy:参数为条件变量
-
pthread_cond_wait:
-
第一个参数为条件变量的地址
-
第二个参数为保护条件所对应的互斥锁的互斥变量的地址
-
-
pthread_cond_signal和pthread_cond_broadcast:参数为条件变量
-
-
实战
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h> pthread_mutex_t mutex; pthread_mutex_t mutex1; pthread_cond_t cond; int g_data = 0; void* thread1(void *arg) { static int i; printf("thread1:%ld\n",(unsigned long)pthread_self()); printf("thread1:param = %d\n",*((int*)arg)); while(1){ pthread_cond_wait(&cond,&mutex); pthread_mutex_lock(&mutex1); sleep(1); printf("==============\n"); g_data = 0; i++; if(i == 6){ exit(0); } pthread_mutex_unlock(&mutex1); } } void* thread2(void *arg) { printf("thread2:%ld\n",(unsigned long)pthread_self()); printf("thread2:param = %d\n",*((int*)arg)); while(1){ pthread_mutex_lock(&mutex1); pthread_mutex_lock(&mutex); sleep(1); printf("t2:g_data = %d\n",g_data); g_data++; if(g_data == 3){ pthread_cond_signal(&cond); } pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex1); sleep(2); } pthread_exit(NULL); } void* thread3() { printf("thread3:%ld\n",(unsigned long)pthread_self()); while(1){ pthread_mutex_lock(&mutex1); pthread_mutex_lock(&mutex); sleep(1); printf("t3:g_data = %d\n",g_data); g_data++; if(g_data == 3){ pthread_cond_signal(&cond); } pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex1); sleep(2); } pthread_exit(NULL); } int main() { pthread_t t1; pthread_t t2; pthread_t t3; int ret; int param = 100; pthread_mutex_init(&mutex,NULL); pthread_mutex_init(&mutex1,NULL); ret = pthread_cond_init(&cond,NULL); if(ret != 0){ printf("cong init error\n"); } ret = pthread_create(&t1,NULL,thread1,(void*)¶m); if(ret < 0){ printf("thread1 create error\n"); } ret = pthread_create(&t2,NULL,thread2,(void*)¶m); if(ret < 0){ printf("thread2 create error\n"); } ret = pthread_create(&t3,NULL,thread3,NULL); if(ret < 0){ printf("thread3 create error\n"); } pthread_join(t1,NULL); pthread_join(t2,NULL); pthread_join(t3,NULL); pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex1); pthread_cond_destroy(&cond); return 0; }