关于线程

什么是线程?其实线程就是一个轻量级的进程,在Linux系统里面,一个进程可以包含多个异步执行的线程,就是一个进程在宏观上表现为处理多个事件。
Linux的线程实现是在核外进行的,核内提供的是创建进程的接口do_fork()。内核提供了两个系统调用__clone()和fork (),最终都用不同的参数调用do_fork()核内API。当然,要想实现线程,没有核心对多进程(其实是轻量级进程)共享数据段的支持是不行的,因此,do_fork()提供了很多参数,包括CLONE_VM(共享内存空间)、CLONE_FS(共享文件系统信息)、CLONE_FILES(共享文件描述符表)、CLONE_SIGHAND(共享信号句柄表)和CLONE_PID(共享进程ID,仅对核内进程,即0号进程有效)。当使用fork系统调用时,内核调用do_fork()不使用任何共享属性,进程拥有独立的运行环境,而使用pthread_create()来创建线程时,则最终设置了所有这些属性来调用__clone(),而这些参数又全部传给核内的do_fork(),从而创建的线程拥有共享的运行环境,只有栈是独立的,由 __clone()传入。

Linux线程在核内是以轻量级进程的形式存在的,拥有独立的进程表项,而所有的创建、同步、删除等操作都在核外pthread库中进行。pthread 库使用一个管理线程(__pthread_manager(),每个进程独立且唯一)来管理线程的创建和终止,为线程分配线程ID,发送线程相关的信号(比如Cancel),而主线程(pthread_create())的调用者则通过管道将请求信息传给管理线程。

为什么要使用多线程?
现在假设有一个进程是处理实时输入的数据,并进行一系列的处理然后产生输出数据,若没有采用多线程的话,只能是同步的执行:数据输入,处理,输出,在进行第二个数据的输入。。。。,这样循环同步处理,如果采用多线程,就可以采用多个线程进行时间的处理,如:一个线程处理数据的输入部分,而另一个线程处理数据的输出部分程序,这样 上面的问题就避免了;
进程和线程的区别?
        不同的进程在不同的地址空间进行执行,然而同一个进程的多个线程共享相同的地址空间(这样线程是很节省资源的);
        进程的执行一般是相当独立的,进程间的同步性有内核控制,而同一个进程的不同线程间一般是存在数据交换的(这也是多线程的产生的原因之一),这一机制是有进程控制的;
        进程的切换要不线程花费更多的时间;
        线程间通讯更加的简单,途径更多(因为他们共享内存空间,代码段等);
用户空间的线程和内核空间线程
线程可以同时存在于用户空间和内核空间;
在用户空间,线程的创建,控制,和撤销都是通过线程库进行的(也就加#include <pthread.h>),用户空间线程对内核是透明的,用户空间的线程调度开销比较小,缺点是不能预调度,而且,在进行一个多任务处理的几个用户线程,一旦有一个碰亏,那么内核结束此进程;
………………………………………………
gcc –o xxxxx –lpthread xxxxx.c//手动链接线程库
……………………………………………
在内核空间,线程的创建,控制,和撤销都是通过内核进行的,而且,内核空间的多个线程在进行多任务处理时,是可以进行预调度的,而且,一个线程的阻塞,不会导致整个进程的阻塞;一般的系统调用就会产生内核线程;
用户空间的线程和内核空间线程存在映射机制;
线程级数据--------TSD
在单进程的任务处理中,变量有局部变量和全局变量,在多线程里,有一种叫做TSD(进程相关数据)的东东,它对于某个线程来说是全局的,对于进程来说是局部的;
进程相关数据的创建,设置,和 删除:
创建:
int pthread_key_create(
pthread_key_t *key,/*分配的键,所有线程共享,但是不同的线程可以为它赋不同的值;*/
void (*destructor) (void *)//销毁函数;
);
。。。。。。。。。。。。。。。。。。。。。。。。
#include <pthread.h>
pthread_key_t key;
int ret;
ret = pthread_key_create(&key, NULL);//默认的处理
ret = pthread_key_create(&key, destructor);
。。。。。。。。。。。。。。。。。。。。。。。
删除:
int pthread_key_delete(pthread_key_t key);
。。。。。。。。。。。。。。。。。。。。。。。
#include <pthread.h>
pthread_key_t key;
int ret;
ret = pthread_key_delete(key);
 
赋值:
int pthread_setspecific(pthread_key_t key, const void *value);
 
获取key值:
 
int pthread_getspecific(pthread_key_t key);
 
1,创建线程
int pthread_create(
pthread_t *tid,//线程标示符的指针
const pthread_attr_t *tattr,//设置线程属性,如果为NULL,就是默认属性;
void*(*start_routine)(void *),/*线程开始运行的函数入口,其实他是一个函数指针,该指针只想一个返回值为指针类型的函数*/
void *arg//运行函数的参数,传递给上面的函数
);
函数成功执行,会返回一个0,其他的任何返回值都是错误的代码;
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void* a(void* b)
{
int id;
while(1)
printf("x\n");
printf(“id\n”,pthread_self());
return NULL;
}
int main ()
{
pthread_t thread_id;
pthread_create(&thread_id,NULL,a,NULL);
while (1)
printf("c");
printf(“id\n”,pthread_self());//获取线程的线程ID;
return 0;
}
}。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
线程有两种状态
joinable:默认状态,当线程函数自己返回退出时或pthread_exit时都不会释放线程所占用堆栈和线程描述符,只有当你调用了pthread_join之后这些资源才会被释放。
unjionable: 线程函数自己返回退出时或pthread_exit时都会释放线程所占用堆栈和线程描述符。通过pthread_detach(thread_id)设置;
2,等待线程终止函数;
int pthread_join(
thread_t tid,//等待要结束线程的ID,该线程的状态必须是jionable;
void **status//存放等待线程结束时返回的值,通常为NULL;
);
当等待的线程已经终止时,那么这个函数就会立即返回。
线程退让函数:
int sched_yield(void);
当一个线程执行此函数时,就会退出执行,然后就会让与其优先级相同或更高的进程执行;
设置线程优先级:
int pthread_setschedparam(
pthread_t tid, 
int policy,//调度策略
const struct sched_param *param/* param是struct sched_param类型的指针,仅包含sched_priority成员,指明该优先级*/
);
调度策略包括:
SCHED_OTHER--------分时调度,线程创建时的默认状态,优先级都是0;
SCHED_RR-----------轮换调度策略;
SCHED_FIFO---------先进先出策略,适用于超级用户线程;
获取线程优先级:
int pthread_getschedparam(
pthread_t tid,
int policy,
struct schedparam *param
)
有时还可向线程发送信号如:pthread_kill(id,signal)://信号的接受者和发送者属于同一个进程;
终止一个线程:
一个线程可以通过三种途径结束:
1)      调用pthread_exit()函数;
2)      根据POSIX 提供的pthread_cancel()函数;
3)      主动返回;
简单总结 仅供参考
以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
### 回答1: 下面是一个关于创建线程的 Python 代码示例: ``` import threading class MyThread(threading.Thread): def __init__(self, thread_id, name, counter): threading.Thread.__init__(self) self.thread_id = thread_id self.name = name self.counter = counter def run(self): print("开始线程:" + self.name) print_time(self.name, self.counter, 5) print("退出线程:" + self.name) def print_time(thread_name, delay, counter): while counter: time.sleep(delay) print("%s: %s" % (thread_name, time.ctime(time.time()))) counter -= 1 thread1 = MyThread(1, "Thread-1", 1) thread2 = MyThread(2, "Thread-2", 2) thread1.start() thread2.start() thread1.join() thread2.join() print("退出主线程") ``` 在这段代码中,我们定义了一个 `MyThread` 类,继承自 Python 中的 `threading.Thread` 类。在这个类中,我们重写了 `run` 方法,来执行线程的任务。接着,我们创建了两个线程对象,并启动它们。最后,使用 `join` 方法等待两个线程执行完毕。 ### 回答2: 在Python中,可以使用`threading`模块来创建和管理线程。下面是一个简单的示例代码,使用Python的类来实现线程: ```python import threading import time class MyThread(threading.Thread): def __init__(self, name): threading.Thread.__init__(self) self.name = name def run(self): print(f"线程 {self.name} 启动") # 执行线程任务 for i in range(5): print(f"线程 {self.name}: 执行任务 {i}") time.sleep(1) print(f"线程 {self.name} 结束") # 创建两个线程对象 thread1 = MyThread("线程1") thread2 = MyThread("线程2") # 启动线程 thread1.start() thread2.start() # 等待线程完成 thread1.join() thread2.join() print("主线程结束") ``` 这个示例代码定义了一个`MyThread`类,继承自`threading.Thread`类,重写了`run`方法,该方法是线程的入口点。在`run`方法中,我们定义了线程要执行的任务。 然后,我们创建了两个`MyThread`对象,分别命名为"线程1"和"线程2"。接着,我们分别启动这两个线程,并使用`join`方法等待线程执行完毕。 最后,主线程打印出 "主线程结束",表示主线程的执行也结束了。 这段代码演示了如何使用Python的类来创建和管理线程。每个线程执行自己的任务,而不会干扰其他线程的执行。使用类可以方便地管理线程,并提供更好的代码组织和可维护性。 ### 回答3: 下面是一个使用Python类编写的关于线程的代码示例: ```python import threading import time # 创建一个继承自Thread类的自定义线程类 class MyThread(threading.Thread): def __init__(self, thread_id, name): threading.Thread.__init__(self) self.thread_id = thread_id self.name = name # 重写run方法,线程启动后执行该方法 def run(self): print("线程 " + self.name + " 正在运行...") time.sleep(2) # 线程休眠2秒 print("线程 " + self.name + " 运行结束.") # 创建线程对象 thread1 = MyThread(1, "Thread 1") thread2 = MyThread(2, "Thread 2") # 启动线程 thread1.start() thread2.start() # 等待线程执行完毕 thread1.join() thread2.join() print("所有线程执行完毕.") ``` 以上代码定义了一个自定义的线程类`MyThread`,该类继承自`Thread`类,并重写了`run`方法,用于线程的实际操作。在`run`方法中,我们模拟了线程运行2秒的操作。然后,创建了两个线程对象`thread1`和`thread2`,并通过调用`start`方法启动它们。最后,调用`join`方法等待线程执行完毕,并输出"所有线程执行完毕"的提示。 这段代码展示了如何使用Python的类编写多线程程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值