用瀑布流做的美食网站,国外引流推广软件,黄浦专业做网站,一般网站banner尺寸是多少#x1f436;博主主页#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️#x1f525;专栏系列#xff1a;线性代数#xff0c;C初学者入门训练#xff0c;题解C#xff0c;C的使用文章#xff0c;「初学」C#xff0c;linux #x1f525;座右铭#xff1a;“不要等到什么都没有了… 博主主页ᰔᩚ. 一怀明月ꦿ ❤️专栏系列线性代数C初学者入门训练题解CC的使用文章「初学」Clinux 座右铭“不要等到什么都没有了才下定决心去做” 大家觉不错的话就恳求大家点点关注点点小爱心指点指点 目录
封装线程
Linux线程互斥
加锁
创建一个锁互斥量
pthread_mutex_lock(mutex);加锁/pthread_mutex_unlock(mutex);解锁
源码实现 封装线程 //开发方
#pragma once#includeiostream
#includestring
#includefunctional
#includepthread.husing namespace std;//typedef functionvoid() func_t
templateclass Tusing func_tfunctionvoid(T);templateclass Tclass Thread{
public:
Thread(func_tT func,const string threadname,T data):_tid(0),_threadname(threadname),_isrunning(false),_func(func),_data(data)
{}static void* Threadroutine(void* args)//类内成员方法其第一个参数是this指针所以会导致编译错误//这里使用static让Thraedroutine成为类的方法
{
(void)args;//仅仅是为了消除警告变量未使用Thread* tsstatic_castThread*(args);ts-_func(ts-_data);
return nullptr;}bool Start(){
int npthread_create(_tid,nullptr,Threadroutine,this);//把当前对象传递给线程执行的方法if(n0)
{
_isrunningtrue;
return true;}
else return false;}bool Join(){
if(!_isrunning)return true;int npthread_join(_tid,nullptr);if(n0)
{
_isrunningfalse;
return true;}
return false;}bool Isrunning(){
return _isrunning;}string Threadname(){
return _threadname;}
private:
pthread_t _tid;string _threadname;bool _isrunning;func_tT _func;T _data;};//应用方
#includeiostream
#includethread.hpp
#includeunistd.h
#includevectorvoid Print(int num){
while(num)
{
couthello world :num--endl;
sleep(1);
}
}string Getthreadname(){
static int number1;//全局变量char name[64];snprintf(name,sizeof(name),Thread-%d,number);
return name;}int main(){
//**1**
// Thread t(Print,Getthreadname());
// coutis thread running?t.Isrunning()endl;
// t.Start();
// coutis thread running?t.Isrunning()endl;
// t.Join();//**2**
// const int num5;
// vectorThread threads;// for(int i0;inum;i)
// {
// Thread t(Print,Getthreadname());
// threads.push_back(t);
// }// for( auto thread:threads)
// {
// coutthread.Threadname()is running: thread.Isrunning()endl;
// }// for(auto thread:threads)
// {
// thread.Start();
// }// for( auto thread:threads)
// {
// coutthread.Threadname()is running: thread.Isrunning()endl;
// }// //不让主线程退出让主线程等待子线程
// for( auto thread:threads)
// {
// thread.Join();
// }//**3**Threadint t(Print,Getthreadname(),10);t.Start();
t.Join();return 0;} Linux线程互斥 1.直接实验不确定性高 多线程抢票的逻辑 抢票系统 Thread-4 get a ticket:0 Thread-1 get a ticket:-1 Thread-2 get a ticket:-2 票被抢到负数是不合理的 2.看到现象—输出概念 1数据不一致共享资源票 2任何一个时刻只允许一个线程正在访问的资源——临界资源互斥 3我们把我们进程中访问临界资源的代码——临界区被保护起来的重点区域 4互斥任何时刻互斥保证有且只有一个执行流进入临界区访问临界资源通常对临界资源起保护作用 3.解释问题 int cnt0; cnt; 这种操作不是原子的 抢票中的临界区 抢票中的临界区
int ticket 10000;
void Getticket(string name)
{
while (true)
{
if (ticket 0)//判断ticket也是计算
{
usleep(1000); // 模拟抢票的话费时间
printf(%s get a ticket:%d \n, name.c_str(), ticket);
ticket—;//在汇编层面会执行三步
//我的理解读是在每个线程的上下文数据中—是在内存中
}
else
break;
}
// 实际情况还有后续的动作
} CPU的基本功能 算算数运算 逻逻辑运算 中处理内外中断 控控制单元 加锁 加锁牺牲效率为代价的解决安全性问题 1.我们要尽可能的给少的代码加锁 2.一般加锁都是给临界区加锁 根据互斥的定义任何时刻只允许一个线程申请锁成功多个线程申请锁的失败失败的线程怎么办在mutex上阻塞等待其他线程释放掉锁再被唤醒申请锁 申请锁本身是安全的原子的只能一个线程申请成功 一个线程在临界区中访问临界资源的时候可不可能发生切换 可能完全允许因为该线程被切换但是没有解锁其他线程就申请不到锁只能被阻塞就不会发生并发访问数据不一致的问题 创建一个锁互斥量 pthread_mutex_t mutex; pthread_mutex_lock(mutex);加锁/pthread_mutex_unlock(mutex);解锁 在Linux系统中pthread_mutex_lock 是一个 POSIX 线程库提供的函数用于加锁互斥量mutex。它的作用是尝试锁定一个互斥量如果这个互斥量已经被其他线程锁定了则调用线程会被阻塞直到获取到该互斥量为止。 事例 #include stdio.h
#include stdlib.h
#include pthread.h
pthread_mutex_t mutex;int shared_data 0;//公共资源void* thread_function(void* arg) {// 加锁pthread_mutex_lock(mutex);// 访问共享资源shared_data;printf(Thread ID %ld, shared data: %d\n, pthread_self(), shared_data);// 解锁pthread_mutex_unlock(mutex);return NULL;
}int main() {pthread_t tid1, tid2;// 初始化互斥量if (pthread_mutex_init(mutex, NULL) ! 0) {perror(Mutex initialization failed);exit(EXIT_FAILURE);}// 创建线程pthread_create(tid1, NULL, thread_function, NULL);pthread_create(tid2, NULL, thread_function, NULL);// 等待线程结束pthread_join(tid1, NULL);pthread_join(tid2, NULL);// 销毁互斥量pthread_mutex_destroy(mutex);return 0;
}
在上面的示例中我们首先创建了一个互斥量 pthread_mutex_t mutex并在主线程中初始化它。然后创建了两个线程它们会执行 thread_function 函数。在 thread_function 中通过调用 pthread_mutex_lock 来锁定互斥量确保对 shared_data 的访问是互斥的然后进行相应操作最后再用 pthread_mutex_unlock 解锁。
这样就确保了在任意时刻只有一个线程能够访问 shared_data避免了数据竞争问题。请注意对于互斥量的使用需要谨慎处理以避免死锁等问题。 源码实现 main #include iostream#include thread.hpp#include unistd.h#include vectorvoid Print(int num){
while (num){
cout hello world : num-- endl;sleep(1);
}
}string Getthreadname(){
static int number 1; // 全局变量char name[64];snprintf(name, sizeof(name), Thread-%d, number);return name;}int ticket 10000;pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; // 锁有了被定义初始化这是一把全局的锁// 加锁牺牲效率为代价的解决安全性问题
// 1.我们要尽可能的给少的代码加锁
// 2.一般加锁都是给临界区加锁
void Getticket(string name){
while (true){
// 加锁
// 根据互斥的定义任何时刻只允许一个线程申请锁成功多个线程申请锁的失败失败的线程怎么办在mutex上阻塞等待其他线程释放掉锁再被唤醒申请锁
pthread_mutex_lock(mutex); // 申请锁本身是安全的原子的只能一个线程申请成功// 一个线程在临界区中访问临界资源的时候可不可能发生切换
// 可能完全允许因为该线程被切换但是没有解锁其他线程就申请不到锁只能被阻塞
//
if (ticket 0){
usleep(1000); // 模拟抢票的话费时间printf(%s get a ticket:%d \n, name.c_str(), ticket);ticket--;
// 解锁
pthread_mutex_unlock(mutex);
}
else
{
// 解锁
pthread_mutex_unlock(mutex);
break;
}
}
// 实际情况还有后续的动作
}int main(){
string name1 Getthreadname();Threadstring t1(name1, Getticket, name1);string name2 Getthreadname();Threadstring t2(name2, Getticket, name2);string name3 Getthreadname();Threadstring t3(name3, Getticket, name3);string name4 Getthreadname();Threadstring t4(name4, Getticket, name4);t1.Start();
t2.Start();
t3.Start();
t4.Start();t1.Join();
t2.Join();
t3.Join();
t4.Join();
return 0;} thread.hpp #pragma once#includeiostream
#includestring
#includefunctional
#includepthread.husing namespace std;//typedef functionvoid() func_t
templateclass Tusing func_tfunctionvoid(T);templateclass Tclass Thread{
public:
Thread(const string threadname,func_tT func,T data):_tid(0),_threadname(threadname),_isrunning(false),_func(func),_data(data)
{}static void* Threadroutine(void* args)//类内成员方法其第一个参数是this指针所以会导致编译错误//这里使用static让Thraedroutine成为类的方法
{
(void)args;//仅仅是为了消除警告变量未使用Thread* tsstatic_castThread*(args);ts-_func(ts-_data);
return nullptr;}bool Start(){
int npthread_create(_tid,nullptr,Threadroutine,this);//把当前对象传递给线程执行的方法if(n0)
{
_isrunningtrue;
return true;}
else return false;}bool Join(){
if(!_isrunning)return true;int npthread_join(_tid,nullptr);if(n0)
{
_isrunningfalse;
return true;}
return false;}bool Isrunning(){
return _isrunning;}string Threadname(){
return _threadname;}
private:
pthread_t _tid;string _threadname;bool _isrunning;func_tT _func;T _data;};进程是资源的分配单位所以线程并不拥有系统资源而是共享使用进程的资源进程的资源由系统进行分配 pthread_self() 用于获取用户态线程的tid而并非轻量级进程ID 主线程调用pthread_cancel(pthread_self())函数来退出自己 则主线程对应的轻量级进程状态变更成为Z 其他线程不受影响这是正确的正常情况下我们也不会这么做.... 主线程调用pthread_exit只是退出主线程并不会导致进程的退出 如果大家还有不懂或者建议都可以发在评论区我们共同探讨共同学习共同进步。谢谢大家