目录
1、进程和线程
2、线程
3、线程同步之信号量
4、线程同步之互斥锁
5、线程同步之条件变量
1.1、使用进程技术的优势和劣势
优势:
CPU时分复用,单核心CPU可以实现宏观上的并行实现多任务系统需求(多任务的需求是客观的)劣势:
进程间切换开销大进程间通信麻烦而且效率低进程与进程之间天生是隔离的,好处是安全,坏处是进程间通信很麻烦
1.2、线程技术
(1)线程技术保留了进程技术实现多任务的特性。
(2)线程的改进就是在线程间切换和线程间通信上提升了效率。
(3)多线程在多核心CPU上面更有优势。
(1)一种轻量级进程
(2)线程是参与内核调度的最小单元
(3)一个进程中可以有多个线程
2.1线程技术的优势
(1)像进程一样可被OS调度
(2)同一进程的多个线程之间很容易高效率通信
(3)在多核心CPU(对称多处理器架构SMP)架构下效率最大化
多核CPU不能保证多个进程在多个CPU核心上同时运行,但多线程可以保证在多个核心上调度
2.2、线程常见函数
(1)线程创建与回收:
pthread_create 主线程用来创造子线程的pthread_join 主线程用来等待(阻塞)回收子线程pthread_detach 主线程用来分离子线程,分离后主线程不必再去回收子线程(2)线程取消:
pthread_cancel 一般都是主线程调用该函数去取消(让它赶紧死)子线程pthread_setcancelstate 子线程设置自己是否允许被取消pthread_setcanceltype(3)线程函数退出相关:
pthread_exit与return退出pthread_cleanup_pushpthread_cleanup_pop(4)获取线程id:
pthread_self
任务:用户从终端输入任意字符然后统计个数显示,输入end则结束
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <pthread.h> #include <stdlib.h> #include <semaphore.h> char buf[200]; sem_t sem; unsigned int flag = 0; void *func(void *arg); int main(void) { pthread_t th = -1; int ret = -1; sem_init(&sem, 0, 0); // 创建一个子线程 ret = pthread_create(&th, NULL, func, NULL); if (ret != 0) { printf("error\n"); exit(-1); } printf("请输入一个字符串,以回车结尾:\n"); while (scanf("%s", buf)) { if (!strcmp("end", buf)) { printf("退出\n"); flag = 1; sem_post(&sem); break; } //主线程在收到用户输入的字符串,并且确认不是end后,就去发信号激活子线程来计数。 sem_post(&sem); } // 回收子进程 ret = pthread_join(th, NULL); if (ret != 0) { printf("pthread_join error.\n"); exit(-1); } printf("子线程回收成功\n"); sem_destroy(&sem); return 0; } // 子线程 void *func(void *arg) { // 被唤醒,没有收到激活信息时会一直阻塞在这里 sem_wait(&sem); // 子线程需要有一个循环,否则打印一次就退出了 while (flag == 0) { printf("%d个字符\n", strlen(buf)); memset(buf, 0, sizeof(buf)); sem_wait(&sem); // 每打印一次都要阻塞,等待下一次激活 } }(1)什么是互斥锁
互斥锁又叫互斥量(mutex)相关函数:pthread_mutex_init pthread_mutex_destroy pthread_mutex_lock pthread_mutex_unlock(2)互斥锁和信号量的关系:可以认为互斥锁是一种特殊的信号量
(3)互斥锁主要用来实现关键段代码保护
(4)互斥锁可以实现上节代码的功能,通过上锁和解锁以及sleep()实现,但并非互斥锁的标准用法,代码效率很低
相关函数
pthread_cond_init pthread_cond_destroy
pthread_cond_wait pthread_cond_signal/pthread_cond_broadcast
代码实践(条件变量和互斥锁需要共同使用,子线程里的互斥锁也是有意义的)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdlib.h> char buf[200]; pthread_mutex_t mutex; pthread_cond_t cond; unsigned int flag = 0; void *func(void *arg); int main(void) { pthread_t th = -1; int ret = -1; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); // 创建一个子线程 ret = pthread_create(&th, NULL, func, NULL); if (ret != 0) { printf("error\n"); exit(-1); } printf("请输入一个字符串,以回车结尾:\n"); while (1) { scanf("%s", buf); // 阻塞 pthread_cond_signal(&cond); // 条件满足会发送信号,pthread_cond_wait()不再阻塞 if (!strcmp("end", buf)) { printf("退出\n"); flag = 1; break; } } // 回收子进程 ret = pthread_join(th, NULL); if (ret != 0) { printf("pthread_join error.\n"); exit(-1); } printf("子线程回收成功\n"); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); return 0; } // 子线程 void *func(void *arg) { // 子线程需要有一个循环,否则打印一次就退出了 while (flag == 0) { pthread_mutex_lock(&mutex); pthread_cond_wait(&cond, &mutex); printf("%d个字符\n", strlen(buf)); memset(buf, 0, sizeof(buf)); pthread_mutex_unlock(&mutex); } }
文章参考朱友鹏老师物联网课程整理