章丘区当地网站建设哪家好,个人网站建设策划书怎么写,建设主题网站一般要经历的顺序,百度信息流广告位置线程概述
同一个程序中的所有线程均会独立执行相同程序#xff0c;且共享同一份全局内存区域#xff1b;
进程是CPU分配资源的最小单位#xff0c;线程是操作系统调度执行的最小单位#xff1b;
Linux环境下#xff0c;线程的本质就是进程#xff1b;
ps -Lf pid且共享同一份全局内存区域
进程是CPU分配资源的最小单位线程是操作系统调度执行的最小单位
Linux环境下线程的本质就是进程
ps -Lf pid查指定进程LWP号线程号 线程和进程的区别
1. 进程间的信息难以共享除只读代码段父子进程并未共享内存 线程共享信息方便快速进程、父进程、进程组、会话ID文件描述符表当前工作目录文件权限掩码虚拟地址空间除栈、.text但超线程ID、信号掩码、error变量、调度策略和优先级、栈、本地变量不共享
2. fork创建进程代价较高 创建线程比创建进程快一个数量级以上
线程操作
/*#include pthread.h一般情况下main所在线程为主线程/main线程其余都成为子线程pthread_t pthread_self(void);功能获取当前线程IDint pthread equal(pthread_t tl,pthread_t t2);功能比较两个线程号是否相等不同操作系统pthread_t类型实现不一样有可能是结构体int pthread_create(pthread t *thread, const pthread attr t *attr,void *(*start_routine) (void *) void *arg);功能创建一个子线程调度的基本单位参数thread - 传出参数线程创建成功子线程ID会写入该变量attr - 设置线程的属性默认值 - NULLstart_rountine - 函数指针子线程需要处理的逻辑代码arg - 给start_rountine使用传参返回值成功 - 0失败 - 错误号与errno不同获取错误号信息char* strerror(int errnum);void pthread_exit(void *retval);功能终止一个当前调用线程参数retval - 传递一个指针作为一个返回值可以在pthread_join中获取返回值 没有任何返回值int pthread_join(pthread_t thread,void **retval);功能和一个已经终止的线程进行连接回收子线程的资源这个函数是阻塞函数调用一次只能回收一个子线程一般在主线程中去使用参数thread - 需要回收的子线程IDretval - 接收子线程退出的返回值返回值成功 - 0失败 - 0int pthread_detach(pthread_t thread);功能分离一个线程将线程标记分离线程终止时自动释放资源给系统1. 不能多次分离不可预料2. 不能去连接一个已经分离的线程会报错join参数需要分离的线程ID返回值成功 - 0失败 - errorint pthread_cancel(pthread_t thread);功能取消线程让线程终止中途暂停但并不是立马终止而是当一个子线程执行到一个取消点线程才会终止取消点系统规定好的一些系统调用可以粗略认为是用户去到内核区的切换这个位置
*/
创建线程
#include iostream
#include pthread.h
#include cstdio
#include string.h
#include unistd.h
using namespace std;void* callback(void *arg){cout子线程....*((int*)arg)endl;return NULL;
}int main(){pthread_t tid;int num 10;int ret pthread_create(tid , NULL , callback , (void*)num);if(ret ! 0){char* str strerror(ret);couterror: strendl;}for(int i 0 ; i5 ; i){coutiendl;}sleep(1);return 0;
}
终止线程
#include iostream
#include pthread.h
#include cstdio
#include string.h
#include unistd.h
using namespace std;void* callback(void *arg){char buf[1024];sprintf(buf , 子线程....%ld , pthread_self());coutbufendl;return NULL;
}int main(){// 创建子线程pthread_t tid;int ret pthread_create(tid , NULL , callback , NULL);if(ret ! 0){char* str strerror(ret);coutstrendl;}for(int i 0 ; i100 ; i){coutiendl;}cout子线程....tidendl;cout主线程....pthread_self()endl;pthread_exit(NULL);// 主线程退出不会影响正常运行的线程return 0; // 进程退出 所有子线程立刻终止
}
链接已终止的线程
#include iostream
#include pthread.h
#include cstdio
#include string.h
#include unistd.h
using namespace std;int val 10;void* callback(void *arg){char buf[1024];sprintf(buf , 子线程....%ld , pthread_self());coutbufendl;// sleep(3);// return NULL; // pthread_exit(NULL);// int val 10; // 局部变量pthread_exit((void*)val);
}int main(){// 创建子线程pthread_t tid;int ret pthread_create(tid , NULL , callback , NULL);if(ret ! 0){char* str strerror(ret);coutstrendl;}for(int i 0 ; i5 ; i){coutiendl;}cout子线程....tidendl;cout主线程....pthread_self()endl;int* ptr;if(pthread_join(tid , (void **)ptr) ! 0){char* str strerror(ret);coutstrendl;}cout回收子线程成功: *(int *)ptrendl;pthread_exit(NULL);// 主线程退出不会影响正常运行的线程return 0; // 进程退出 所有子线程立刻终止
}
线程分离
#include iostream
#include pthread.h
#include cstdio
#include string.h
#include unistd.h
using namespace std;void* callback(void* arg){cout我的ID: pthread_self()endl;return NULL;
}int main(){// 创建pthread_t tid;int ret pthread_create(tid , NULL , callback , NULL);if(ret ! 0){char* str strerror(ret);couterror1: strendl;}cout父线程pthread_self()子线程tidendl;//子线程分离ret pthread_detach(tid);if(ret ! 0){char* str strerror(ret);couterror2: strendl;}//对分离子线程进行连接ret pthread_join(tid,NULL);if(ret ! 0){char* str strerror(ret);couterror3: strendl;}pthread_exit(NULL);return 0;
}
线程取消
#include iostream
#include pthread.h
#include cstdio
#include string.h
#include unistd.h
using namespace std;void* callback(void* arg){cout我的ID: pthread_self()endl;for(int i 0 ; i5 ; i){cout子线程iendl;}return NULL;
}int main(){// 创建pthread_t tid;int ret pthread_create(tid , NULL , callback , NULL);if(ret ! 0){char* str strerror(ret);couterror1: strendl;}// 取消线程pthread_cancel(tid);for(int i 0 ; i10 ; i){coutiendl;}cout父线程pthread_self()子线程tidendl;pthread_exit(NULL);return 0;
}
线程属性 /*
int pthread_attr_init(pthread_attr_t *attr);初始化线程属性变量int pthread_attr_destroy(pthread_attr_t *attr);释放线程属性资源int pthread_attr_getdetachstate(const pthread_attq_t *attr, int* detachstate);获取线程分离的状态属性int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);设置线程分离的状态属性*/#include iostream
#include pthread.h
#include cstdio
#include string.h
#include unistd.h
using namespace std;void* callback(void* arg){cout我的ID: pthread_self()endl;return NULL;
}int main(){// 创建线程属性变量pthread_attr_t attr;pthread_attr_init(attr);pthread_attr_setdetachstate(attr , PTHREAD_CREATE_DETACHED);// 获取线程栈的大小size_t size;pthread_attr_getstacksize(attr , size);cout子线程占空间大小sizeendl;// 创建pthread_t tid;int ret pthread_create(tid , attr , callback , NULL);if(ret ! 0){char* str strerror(ret);couterror1: strendl;}cout父线程pthread_self()子线程tidendl;pthread_attr_destroy(attr);ret pthread_join(tid,NULL);if(ret ! 0){char* str strerror(ret);couterror3: strendl;}pthread_exit(NULL);return 0;
}
线程同步
必须确保多个线程不会同时修改同一变量或者某一线程不会读取正在由其他线程修改的变量
临界区是指访问某一共享资源的代码片段这段代码的执行应该为原子操作不能分割
互斥锁
使用互斥锁来确保仅有一个线程可以访问某项共享资源保证原子访问
互斥锁由两种状态锁定/未锁定试图对锁定的互斥锁再加锁会导致线程阻塞/报错取决于加锁使用的方法
线程加锁成为互斥锁的所有者只有所有者才能解锁
/*
互斥量的类型 pthread_mutex_t
int pthread_mutex_init(pthread_mutex_t *restrict mutexconst pthread_mutexattr_t *restrict attr);功能初始化互斥锁参数mutex - 需要初始化的互斥锁attr - 互斥锁相关属性 NULLrestric - C语言修饰符被修饰的指针不能由另外的指针进行操作
int pthread_mutex_destroy(pthread_mutex_t *mutex);释放互斥量的资源
int pthread_mutex_lock(pthread_mutex_t *mutex);加锁 如果有线程已经加锁只能阻塞等待
int pthread_mutex_trylock(pthread_mutex_t *mutex);尝试加锁加锁失败不会阻塞会直接返回
int pthread_mutex_unlock(pthread_mutex_t *mutex);释放锁
*/
死锁
多个进程在执行过程中因争夺共享资源而造成的一种互相等待的现象
导致死锁的三个主要原因
1. 加锁忘记释放
2. 重复枷锁
3. 线程之间对于锁循环等待
读写锁
读写锁允许多个读出但只允许一个写入
1. 如果有其他线程读数据则允许其他线程执行读操作但不允许写操作
2. 有其他线程写数据则其他线程不允许读/写
3. 写是独占的写的优先级高
/*读写锁的类型 pthread_rwlock_tint pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
*/
// 案例创建8个线程操作同一个全局变量
// 3个线程不定时写一个全局变量其余5个线程不定时读全局变量
#include iostream
#include pthread.h
#include cstdio
#include unistd.h
using namespace std;int num 1;
// pthread_mutex_t mutex;
pthread_rwlock_t rwlock;void* wnum(void* arg){while(1){// pthread_mutex_lock(mutex);pthread_rwlock_wrlock(rwlock);num;printf(write , tid: %ld , num : %d\n , pthread_self() , num);// pthread_mutex_unlock(mutex);pthread_rwlock_unlock(rwlock);sleep(1);}return NULL;
}void* rnum(void* arg){while(1){// pthread_mutex_lock(mutex);pthread_rwlock_rdlock(rwlock);printf(read , tid: %ld , num : %d\n , pthread_self() , num);// pthread_mutex_unlock(mutex);pthread_rwlock_unlock(rwlock);sleep(1);}return NULL;
}int main(){// pthread_mutex_init(mutex , NULL);pthread_rwlock_init(rwlock , NULL);// 创建3个写线程 5个读线程pthread_t wtids[3] , rtids[5];for(int i 0 ; i3 ; i){pthread_create(wtids[i] , NULL , wnum , NULL);}for(int i 0 ; i5 ; i){pthread_create(rtids[i] , NULL , rnum , NULL);}// 设置线程分离for(int i 0 ; i3 ; i){pthread_detach(wtids[i]);}for(int i 0 ; i5 ; i){pthread_detach(rtids[i]);}pthread_exit(NULL);// pthread_mutex_destroy(mutex);pthread_rwlock_destroy(rwlock);return 0;
}
生产者消费者模式
多生产者 - 容器 - 多消费者
阻塞 - 通知机制需要条件变量和信号量来进行实现
条件变量 - 通过条件变量来唤醒阻塞进程
信号量 - 一定程度上表示资源的多少
/*信号量的类型 sem_tint sem_init(sem_t *sem, int pshared,unsigned int value);初始化信号量参数sem - 信号量变量的地址pshared - 0用在线程非0用在进程value - 信号量中的值int sem_destroy(sem_t *sem);释放资源int sem_wait(sem_t *sem);加锁 对信号量的值减1如果值为0则阻塞int sem_trywait(sem_t *sem);尝试int sem_timedwait(sem_t *sem, const struct timespec *abs timeout);等待多少时间int sem_post(sem_t *sem);解锁 对信号量的值加1int sem_getvalue(sem_t *sem, int *sval);获取值
*/
// 生产者消费者模型 粗略版本
#include iostream
#include pthread.h
#include cstdio
#include unistd.h
#include cstdlib
#include semaphore.h
using namespace std;// 创建一个互斥锁
pthread_mutex_t mutex;
// 创建两个信号量
sem_t p , c;class Node{
public:int num;Node* next;
};Node* head NULL;void* pro(void* arg){// 不断创建节点添加到链表while(1){sem_wait(p);pthread_mutex_lock(mutex);Node* newNode new Node();newNode-next head;head newNode;newNode-num rand()%100;printf(add node , num: %d , tid: %ld\n , newNode-num , pthread_self()); pthread_mutex_unlock(mutex);sem_post(c);usleep(1000);}return NULL;
}void* cus(void* arg){while(1){sem_wait(c);pthread_mutex_lock(mutex);Node* cur head;head head-next;printf(del node : %d , tid : %ld\n , cur-num , pthread_self());delete(cur);cur NULL;pthread_mutex_unlock(mutex);sem_post(p);usleep(1000);}return NULL;
}int main(){pthread_mutex_init(mutex , NULL);sem_init(p , 0 , 5);sem_init(c , 0 , 0);// 5个生产者5个消费者pthread_t ptids[5] , ctids[5];for(int i 0 ; i5; i){pthread_create(ptids[i] , NULL , pro , NULL);pthread_create(ctids[i] , NULL , cus , NULL);}for(int i 0 ; i5 ; i){pthread_detach(ptids[i]);pthread_detach(ctids[i]);}while(1){sleep(10);}pthread_mutex_destroy(mutex);pthread_exit(NULL);return 0;
}