1、线程概念
由于进程的地址空间是私有的,因此在进程间上下文切换时,系统开销比较大,为了提高系统的性能,许多操作系统规范里引入了轻量级进程的概念,也被称为线程。
在同一个进程中创建的线程共享该进程的地址空间Linux里同样用task_struct来描述一个线程。线程和进程都参与统一的调度线程通过tid区分。
2、线程接口
1、pthread_create: 创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Compile and link with -pthread. //编译时需要链接pthread库
例如:gcc pthread_create.c -lpthtread
参数:
thread --- 线程ID
attr --- 线程属性,一般为NULL
start_routine --- 线程执行函数
arg --- 向start_routine传参的参数
返回值:
成功:0
失败:错误码
2、pthread_exit: 退出线程
void pthread_exit(void *retval);
参数: retval --- 返回值
3、pthread_cancel: 取消线程
4、pthread_join: 等待线程退出,并给线程回收资源
int pthread_join(pthread_t thread, void **retval);
参数:
thread --- 线程ID
retval --- 获取线程的返回值pthread_exit
5、pthread_detach: 分离线程,线程结束时自动回收资源
3、信号量
1、多线程共享同一个进程的地址空间
优点:线程间很容易进行通信, 通过全局变量实现数据共享和交换
缺点:多个线程同时访问共享对象时,需要引入同步和互斥机制
2、同步(synchronization)指的是多个任务(线程)按照约定的顺序相互配合完成一件事情
(1)信号量代表某一类资源,其值表示系统中该资源的数量
(2)信号量是一个受保护的变量,只能通过三种操作来访问
* 初始化 sem_init
* P操作(申请资源) sem_wait
* V操作(释放资源) sem_post
信号量的值为非负整数
二值信号量:0 (资源不可用) 1(资源可用)
计数信号量: 0 ~ n
![](信号量.png)
1、sem_init: 初始化信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数: sem --- 初始化的信号量
pshared --- 0(线程间使用)
value --- 信号量的值
返回值:成功: 0
失败: -1, 设置errno
2、sem_wait: p操作
int sem_wait(sem_t *sem);
返回值:成功: 0
失败: -1, 设置errno
3、sem_post:v操作
int sem_post(sem_t *sem);
返回值:成功: 0
失败: -1, 设置errno
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <semaphore.h> |
代码如下:
char buf[100]; sem_t sem1; //生产者 sem_t sem2; //消费者 void *thread_func(void *arg) { while (1) { //p操作:申请资源 sem_wait(&sem2); printf("buf: %s\n", buf); //v操作:释放资源 sem_post(&sem1); } } int main(int argc, char *argv[]) { pthread_t thread; if (0 > sem_init(&sem1, 0, 1)) { perror("sem_init1"); return -1; } if (0 > sem_init(&sem2, 0, 0)) { perror("sem_init2"); return -1; } int err = pthread_create(&thread, NULL, thread_func, NULL); if (err != 0) { fprintf(stderr, "pthread_create: %s\n", strerror(err)); return -1; } while (1) //生产者 { //p操作:申请资源 sem_wait(&sem1); printf("Input: "); fgets(buf, sizeof(buf), stdin); //v操作:释放资源 sem_post(&sem2); } return 0; } |
04、互斥锁
1、概念:
引入互斥(mutual exclusion)锁的目的是用来保证共享数据操作的完整性。
互斥锁主要用来保护==临界资源==
每个临界资源都由一个互斥锁来保护,任何时刻最多只能有一个线程能访问该资源
线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。如果无法获得锁,线程会阻塞直到获得锁为止
2、Ubuntu帮助文档安装ubuntu man手册不全,使用下面的方法安装:
sudo apt-get install manpages-de manpages-de-dev manpages-dev glibc-doc manpages-posix-dev manpages-posix
3、互斥锁使用:
* 初始化 pthread_mutex_init
* 加锁: pthread_mutex_lock
* 解锁: pthread_mutex_unlock