公共资源
也称为共享资源,是指可以被多个并发进程或线程共同访问(读取或写入)的系统资源。
临界资源
是公共资源的一个子集。特指那些一次仅允许一个进程或线程访问的公共资源。如果一个进程正在使用它,其他试图访问该资源的进程必须等待,直到当前访问完成。
临界区
指进程中访问临界资源的那段代码。它不是资源本身,而是操作资源的代码段。 目标:确保当一个进程在临界区内执行时,其他任何进程都不能进入其自身的临界区(访问同一个临界资源)。
互斥
是一种机制、原则或属性,用于保证对临界资源的互斥访问。它要求在任何时刻,最多只能有一个执行流(进程或线程)进入与某一临界资源相关的临界区。
互斥量
作用:用于线程的互斥,以避免对临界资源访问时冲突问题。
用法:通常在进入临界区之前加锁,退出临界区时解锁。
类型:pthread_mutex_t定义变量:pthread_mutex_t mutex;
操作:初始化(两种方法)1. pthread_mutex_init(&mutex, NULL);//此方法需要销毁2. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//此方法不需要销毁加锁: pthread_mutex_lock(&mutex);已经被加锁,线程阻塞。pthread_mutex_trylock(&mutex);已经被加锁,线程不阻塞,通过返回值判断所得状态。解锁:pthread_mutex_unlock(&mutex);销毁: pthread_mutex_destroy(&mutex);
死锁
什么是死锁:
多进程或多线程,在竞争资源的时候,由于互相抢占而导致僵死的状态叫做死锁。
死锁是由于一方拿到资源不释放。而其他线程或进程无法获取资源导致。
解决死锁的方法:
使用非阻塞方式拿锁,不等待。
- 拿到做做事,拿不到锁做其他的事。
获取多个互斥量时规定拿锁的顺序。
- 如有A、B两个锁,规定先拿A再拿B,拿不到A就不允许拿B。
互斥量允许强制剥夺。
- 如果有线程占用互斥量时间过长,允许其他线程强制剥夺互斥量。
示例代码
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>#include <pthread.h>#define MAX_THREADS (5) // 最大的线程个数static int is_running = 1;
// 针对 is_running 这个资源的锁
static pthread_mutex_t running_lock;// 临界资源i
static long int i = 0;
// 针对 i 这个资源的锁,并初始化
static pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;
// 定义一个线程处理函数
void * mythread(void* data) {long int arg = (long int)data;char charactor = 'a' + arg;while(1) {int run;pthread_mutex_lock(&running_lock);run = is_running;pthread_mutex_unlock(&running_lock);if (!run)break;// 对i 这个临界资源加锁pthread_mutex_lock(&count_lock);if (i == arg) {printf("%c", charactor);fflush(stdout);i = (i + 1) % MAX_THREADS;}// 解锁pthread_mutex_unlock(&count_lock);}return data;
}int main(int argc, char * argv[]) {pthread_t thread[MAX_THREADS];int ret;printf("请输入回车开始和结束线程\n");getchar();// 初始化运行状态锁pthread_mutex_init(&running_lock, NULL);for (long int i = 0; i < MAX_THREADS; i++) {void *varg = (void*)i;ret = pthread_create(&thread[i], NULL, mythread, varg);if (ret) {printf("pthread_create error: %d\n", ret);return 1;}}// 等待回车getchar();pthread_mutex_lock(&running_lock);is_running = 0;pthread_mutex_unlock(&running_lock);// 杀死所有的线程// for (int i = 0; i < MAX_THREADS; i++) {// pthread_cancel(thread[i]);// } // 等待回收资源for (int i = 0; i < MAX_THREADS; i++) {void * pret;pthread_join(thread[i], &pret);printf("pret:%p\n", pret);} // 销毁运行状态锁pthread_mutex_destroy(&running_lock);printf("主进程结束\n");return 0;
}
条件变量:
条件变量是一种线程同步机制,他允许一个线程在某个条件不满足时主动进入等待状态并释放锁,直到另一个线程改变这个条件后再通知其他线程继续运行。
核心思想:以等代查。
定义条件变量:pthread_cond_t mycond;
操作:初始化(两种方法)1. pthread_cond_init(&mycond, NULL);//此方法需要销毁2. pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;//此方法不需要销毁等待条件: pthread_cond_wait(&mycond, &mutex);唤醒等待的线程:pthread_cond_signal(&mycond); // 唤醒一个线程pthread_cond_broadcast(&mycond); // 广播唤醒全部线程。销毁: pthread_cond_destroy(&mycond);
示例代码:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>#include <pthread.h>#define MAX_THREADS (5) // 最大的线程个数static int is_running = 1;
// 针对 is_running 这个资源的锁
static pthread_mutex_t running_lock;// 临界资源i
static long int i = 0;
// 针对 i 这个资源的锁,并初始化
static pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER;
// 定义 i 这个资源的条件变量,并初始化
static pthread_cond_t count_cond = PTHREAD_COND_INITIALIZER;// 定义一个线程处理函数
void * mythread(void* data) {long int arg = (long int)data;char charactor = 'a' + arg;while(1) {int run;// pthread_mutex_lock(&running_lock);run = is_running;// pthread_mutex_unlock(&running_lock);if (!run)break;// 对i 这个临界资源加锁pthread_mutex_lock(&count_lock);while( i != arg && is_running != 0) {pthread_cond_wait(&count_cond, &count_lock);}if (i == arg) {printf("%c", charactor);fflush(stdout);i = (i + 1) % MAX_THREADS;// 唤醒条件变量关联的其他线程。// pthread_cond_signal(&count_cond); //唤醒一个线程pthread_cond_broadcast(&count_cond); //唤醒全部}/* else {// 现在不应当我来打印。解锁睡觉等待条件变化pthread_cond_wait(&count_cond, &count_lock);// 如果返回,说明条件变化,立即加锁做事情}*/// 解锁pthread_mutex_unlock(&count_lock);}return data;
}int main(int argc, char * argv[]) {pthread_t thread[MAX_THREADS];int ret;printf("请输入回车开始和结束线程\n");getchar();// 初始化运行状态锁pthread_mutex_init(&running_lock, NULL);for (long int i = 0; i < MAX_THREADS; i++) {void *varg = (void*)i;ret = pthread_create(&thread[i], NULL, mythread, varg);if (ret) {printf("pthread_create error: %d\n", ret);return 1;}}// 等待回车getchar();pthread_mutex_lock(&running_lock);is_running = 0;pthread_mutex_unlock(&running_lock);// 再次唤醒所有的进程退出。pthread_cond_broadcast(&count_cond); //唤醒全部// 杀死所有的线程// for (int i = 0; i < MAX_THREADS; i++) {// pthread_cancel(thread[i]);// } // 等待回收资源for (int i = 0; i < MAX_THREADS; i++) {void * pret;pthread_join(thread[i], &pret);printf("pret:%p\n", pret);} // 销毁运行状态锁pthread_mutex_destroy(&running_lock);printf("主进程结束\n");return 0;
}
网络IPC
IP 地址(Internet Protocal Address):
IP 地址是记录一个网络设备的逻辑地址。
IP地址的分类:
IPv4: 用 32bit 来标识网络设备(四个字节)
- 192.168.1.100
IPv6:用 128bit 来标识网络设备
- 不稳定,是未来的发展趋势。
端口号(port):
用来记录网路设备上特定进程的关联号码。是一个16位的无符号性整数。
值 1~65535
IP 地址和子网掩码
A类:255.0.0.0
B类:255.255.0.0
C类:255.255.255.0
查看IP地址的命令:
# Windows
ipconfig
# 早期 Linux/UNIX
ifconfig
# Ubuntu Linux
ip a
ip addr
ip address
内容如下:
inet 192.168.33.151/24 brd 192.168.33.255 scope global dynamic noprefixroute ens33# IP 地址: 192.168.33.151
# 广播地址:192.168.33.255
# 子网掩码: /24 表示 (255.255.255.0)IP 地址 & 子网掩码 = 192.168.33.151 & 255.255.255.0 = 192.168.33.0 本网路的地址