线程的基本操作,cpu线程和操作系统线程
线程为什么要用线程?使用fork创建一个流程来执行一个新任务是非常昂贵的。——子进程复制父进程的所有资源。多个进程之间不直接共享内存。进程是系统资源分配的基本单位。线程是进程的基本执行单元。进程的所有任务都在一个线程中执行。如果一个进程想要执行一个任务,它必须有一个线程。一个进程必须至少有一个线程。当一个程序启动时,默认会打开一个线程。这个线程被称为主线程或UI线程。什么是线程?线程是进程中的控制序列。类比:创建一个过程类似于克隆一个族。新‘家’和原‘家’一模一样,但新‘家’完全独立于原‘家’。一个进程包含一个或多个线程,就像一个系列包含一个或多个系列成员一样。家庭的每个成员都在同时做自己的事情,但对于家庭以外的人来说,是家庭在同时做很多事情。家庭的每个成员都是一根线。每个家庭成员都有自己的个人资源,也就是线程都有自己的局部变量。所有家族成员都可以共享这个家族的资源,即同一进程中的所有线程都可以共享当前进程中的全局变量,除了线程本身的局部变量,其他资源都是共享的。注意:在单核处理器上,一次只能运行一个线程。但是对于用户来说,感觉就像执行了多个线程,因为每个线程都在单核CPU上不停地切换。线程的优点和缺点:创建线程比创建进程花费更少。缺点:多线程编程要更加小心,容易出错。多线程很难。补充:把一个任务分成两部分。如果运行在单核处理器上,可能不会更快。除非可以确定该任务运行在多核处理器上,否则这两个部分可以同时执行。线程化的应用需要让用户感觉到他们在同时做多件事情。比如:处理文档的过程,一个线程处理用户编辑,一个线程同时统计用户的字数。当应用程序需要同时处理输入、计算和输出时。可以打开三个线程,分别处理输入、计算、输出。综上所述,高并发编程。线程使用线程的create pthread_create函数:创建一个新线程。同时,指定线程的属性、执行函数和执行函数的参数。prototype:int pthread _ create(pthread _ t * thread,pthread _ attr _ t * attr,void *(start _ routine)(void *),void * arg);
参数:thread:指向新的线程标识符。Attr:用于设置新线程的属性。一般采用默认属性,即参数为NULL。Start_routine:这个线程的处理函数。这个函数的返回类型和参数类型都是void*。Arg:线程处理函数start_routine的参数。返回值:成功:返回0。失败:返回一个错误代码。(错误码,此处省略,其他功能也一样。注意:一旦用fork创建了流程,流程将立即启动,fork后面的代码将被执行。一旦用pthread_create创建了一个线程,新的线程将立即启动并执行相应的线程处理函数。的线程终止pthread_exit函数:在线程函数内部调用该函数终止该线程,返回值由参数retval指定。prototype:void pthread _ exit(void * retval)参数:retval:它指向的数据是线程退出时的返回值。如果不需要接收线程的返回值,设置NULL即可。新增:pthread_join (3)—Linux手册页等待指定线程完成pthread_join函数:等待指定线程完成,获取线程的返回值。prototype:int pthread _ join(pthread _ tth,void * * thread _ return);参数:th:线程标识符,指定等待线程。Thread_return:指向(接收)当前线程的返回值。参数是void**。返回值成功:返回0。失败:返回错误号。使用线程程序的编译器定义宏:_ reentrant 3354 reentrant函数:gcc -D_REENTRANT函数:告诉编译器编译时需要可重用的函数。也就是说,在编译时,编译一些函数的可重入版本。将共享资源给该线程专用。注意:单线程程序中,整个程序是顺序执行的,一个函数在同一时刻只能被一个函数调用。但是,在多线程中,由于并发性,一个函数可能同时被多个函数调用。这个时候这个函数就变成了一个关键性的资源,在调用函数的时候很容易造成处理结果的交互。如果一个函数处于多线程并发环境,每次调用产生的结果是不确定的,我们就说这个函数是不可重入的/线程不安全的。编译时,指定线程库。即gcccxxx-lpthread函数:使用系统默认的NPTL线程库。也就是说,在默认路径中查找库文件libpthread.so。默认路径是/usr/lib和usr/local/lib。一般可以使用以下形式:gcc myth thread . c-o myth thread-d _ reentrant-LP thread示例:
#include pthread.h
#包含stdio.h
#包含stdlib.h
int my _ global
void * my _ thread _ handle(void * arg){
int val
val=*((int *)arg);
printf(新线程开始,arg=%d\n ,val);
my _ global=val
睡眠(3);
pthread _ exit(my _ global);
//不再执行下面一行
printf(新线程结束\ n );
}
int main(void){
pthread _ t mythread
int arg
int ret
void * thread _ return
arg=100
my _ global=1000
printf(my_global=%d\n ,my _ global);
printf(准备创建线程.\ n’);
ret=pthread_create( mythread,0,my_thread_handle,arg);
如果(ret!=0) {
printf(创建线程失败!\ n’);
出口(1);
}
printf(等待线程完成.\ n’);
ret=pthread_join(mythread,thread _ return);
如果(ret!=0) {
printf(pthread_join失败!\ n’);
出口(1);
}
printf(等待线程结束,返回值为%d\n ,*((int *)thread _ return));
printf(my_global=%d\n ,my _ global);
printf(创建线程完成!\ n’);
返回0;
}
线程同步互斥线程互斥:是指同一时刻只允许一个访问者访问一个资源,具有唯一性和排他性。但是互斥不能限制访问者对资源的访问顺序,即访问无序。线程同步(Thread synchronization):是指访问者在互斥的基础上,通过其他机制有序地访问资源(大多数情况下)。问题:同一进程中的线程共享进程的全局变量,如果多个线程同时访问一个全局变量,可能会导致争用。Race:多线程访问共享资源。Linux内核分析(7)-并发和竞争。并发编程中我们常说的竞赛是什么?解决方案:对关键部分使用信号量或互斥体。信号量和互斥量的选择:对于同步和互斥,信号量和互斥量都可以使用。使用时,选择更符合情况的:如果要求最多只允许一个线程进入临界区,就使用互斥体。如果需要多线程之间的执行顺序来满足某个约束,就使用信号量。什么是信号量?此时‘信号量’指的是同一个进程中多个线程之间使用的信号量。即POSIX信号量,而不是System V信号量。(用于进程间的信号量)。用于线程的信号量原理与用于进程间信号量的原理相同。都有P和V操作。信号量表示:sem_t类型。信号量初始化sem_init函数:初始化信号量。prototype:int SEM _ init(SEM _ t * SEM,int pshared,unsigned int value);参数:sem:指向要初始化的信号量。P: 0表示这个信号量是一个在这个进程中使用的“本地信号量”,不再被其他进程共享。0表示信号量可以被其他进程共享,Linux不支持这个信号量。值:信号量的初始值。=0返回值:成功:返回0。失败:返回错误代码。信号量p操作sem_wait函数:信号量p操作。-1函数原型:int SEM _ wait(SEM _ t * SEM);参数:sem:要操作的信号量。返回值:成功:返回0。失败:返回错误代码。信号量v操作sem_post函数:信号量v操作。1函数原型:int SEM _ post(SEM _ t * SEM);参数:sem:要操作的信号量。返回值:成功:返回0。失败:返回错误代码。信号量删除sem_destroy函数:删除信号量。原型:int SEM _ destroy(SEM _ t * SEM);参数:sem:要操作的信号量。返回值:成功:返回0。失败:返回错误代码。示例:
#include pthread.h
#包含信号量. h
#包含字符串. h
#包含stdlib.h
#包含stdio.h
#定义BUFF_SIZE 80
char BUFF[BUFF _ SIZE];
sem _ t sem
静态void * str _ thread _ handle(void * arg)
{
while(1) {
//P(sem) -1
if (sem_wait( sem)!=0) {
printf(sem_wait失败!\ n’);
出口(1);
}
printf(string is: %slen=%d\n ,buff,strlen(buff));
if (strncmp(buff, end ,3)==0) {
打破;
}
}
}
int main(void)
{
int ret
pthread _ t str _ thread
void * thread _ return
ret=sem_init( sem,0,0);
如果(ret!=0) {
printf(sem_init失败!\ n’);
出口(1);
}
ret=pthread_create( str_thread,0,str_thread_handle,0);
如果(ret!=0) {
printf(pthread_create失败!\ n’);
出口(1);
}
while (1) {
fgets(buff,sizeof(buff),stdin);
//V(sem) 1
if (sem_post( sem)!=0) {
printf(sem_post失败!\ n’);
出口(1);
}
if (strncmp(buff, end ,3)==0) {
打破;
}
}
ret=pthread_join(str_thread,thread _ return);
如果(ret!=0) {
printf(pthread_join失败!\ n’);
出口(1);
}
ret=SEM _ destroy(SEM);
如果(ret!=0) {
printf(sem_destroy失败!\ n’);
出口(1);
}
返回0;
}
互斥量什么是互斥量?其效果相当于初始值为1的信号量。
互斥量的初始化pthread _互斥体_初始化功能:初始化互斥量。函数原型:int pthread _ mutex _ init(pthread _ mutex _ t * mutex,pthread _ mutex attr _ t * attr);参数:互斥:指向被初始化的互斥量属性:互斥量的属性,一般取默认属性。返回值:成功:返回0。失败:返回错误码。互斥量的获取线程互斥锁功能:获取互斥量。函数原型:int pthread _ mutex _ lock(pthread _ mutex _ t * mutex);参数:互斥:指向要操作的互斥量。返回值:成功:返回0。失败:返回错误码。互斥量的删除pthread _互斥体_销毁功能:删除互斥量。函数原型:int pthread _ mutex _ destroy(pthread _ mutex _ t * mutex);参数:互斥:指向要操作的互斥量。返回值:成功:返回0。失败:返回错误码。示例:
#include pthread.h
#包含信号量。h
#包含字符串。h
#包含标准库
#包含标准视频
#定义BUFF_SIZE 80
int全局值=1000
pthread _互斥锁
静态void * str _ thread _ handle(void * arg)
{
int I=0;
for(I=0;i i ) {
pthread _ mutex _ lock(lock);
if (global_value 0) {
//工作
睡眠(1);
printf(已售出的票证(%d)到子站(%d)\n ,
global_value,I 1);
}
global _ value-;
pthread _ mutex _ unlock(lock);
睡眠(1);
}
}
int main(void)
{
内部ret
pthread _ t字符串线程
void *线程_返回
int I;
ret=pthread_mutex_init( lock,0);
如果(ret!=0) {
pthread_mutex_init失败!\ n’);
出口(1);
}
ret=pthread_create( str_thread,0,str_thread_handle,0);
如果(ret!=0) {
printf(pthread_create失败!\ n’);
出口(1);
}
for(I=0;i i ) {
pthread _ mutex _ lock(lock);
if (global_value 0) {
//工作
睡眠(1);
printf(已售出的车票(%d)至主站(%d)\n ,
global_value,I 1);
}
global _ value-;
pthread _ mutex _ unlock(lock);
睡眠(1);
}
ret=pthread_join(str_thread,thread _ return);
如果(ret!=0) {
printf(pthread_join失败!\ n’);
出口(1);
}
ret=pthread _ mutex _ destroy(lock);
如果(ret!=0) {
printf(pthread_mutex_destroy失败!\ n’);
出口(1);
}
返回0;
}
什么是线程的条件变量?与互斥不同,条件变量是用来等待的,而不是用来锁定的。条件变量用来自动阻塞一个线程,直到有事情发生。通常,条件变量与互斥体一起使用。变量使我们能够休眠,等待某个条件的出现。条件变量是一种利用线程间共享的全局变量进行同步的机制,主要包括两个动作:线程挂起,等待条件变量的条件成立;使线程“有条件”(给出一个条件信号)。条件检测是在互斥的保护下进行的。如果条件为假,线程会自动阻塞(挂起)并释放互斥体,等待状态改变。如果另一个线程改变了条件,它会通知相关的条件变量,唤醒一个或多个等待它的线程,重新获得互斥体,并重新评估条件。如果两个进程共享可读和可写的内存,则可以使用条件变量来实现两个进程之间的线程同步。条件变量初始化pthread_cond_init函数:初始化条件变量函数的原型:int pthread _ cond _ init(pthread _ cond _ t * cond,const pthread _ cond attr _ t * attr);参数:cond:要操作的条件变量。Attr:设置条件变量的属性。返回值:成功:返回0。失败:返回错误代码。唤醒一个等待线程pthread_cond_signal函数:通知条件变量,唤醒一个等待线程。原型:int pthread _ cond _ signal(pthread _ cond _ t * cond);参数:cond:要操作的条件变量(条件变量指针)。返回值:成功:返回0。失败:返回错误代码。唤醒所有等待这个条件变量的线程pthread_cond_broadcast函数:广播条件变量。原型:int pthread _ cond _ broadcast(pthread _ cond _ t * cond);参数:cond:要操作的条件变量。返回值:成功:返回0。失败:返回错误代码。等待条件变量/timeout唤醒pthread_cond_timedwait函数:等待条件变量cond唤醒,然后唤醒线程,直到有信号或广播,或者绝对超时abstime。prototype:int pthread _ cond _ timed wait(pthread _ cond _ t * cond,pthread _ mutex _ t * mutex,const struct timespec * abst time);参数:cond:要操作的条件变量:mutex: mutex。返回值:成功:返回0。失败:返回错误代码。等待条件变量唤醒pthread_cond_wait函数:等待条件变量cond唤醒(通过信号或广播)。原型:int pthread _ cond _ wait(pthread _ cond _ t * cond,pthread _ mutex _ t * mutex);参数:cond:要操作的条件变量。互斥:互斥。返回值:成功:返回0。失败:返回错误代码。释放/销毁条件变量pthread_cond_destroy函数:销毁条件变量。原型:int pthread _ cond _ destroy(pthread _ cond _ t * cond);参数:cond:要销毁的条件变量。返回值:成功:返回0。失败:返回错误代码。示例:
个人认为,条件变量会为关键资源建立两道防线。第一道防线是在进入和等待醒来之前,第二道防线是在进入临界区之前。条件变量和互斥变量的组合。进入第一道防线时,pthread_mutex_lock锁定互斥体(P操作)。进入第一道防线后,也就是等待被唤醒前,pthread_cond_wait会先挂起当前线程,然后解锁互斥体(V操作)。唤醒时,pthread_cond_wait先锁定互斥体,再唤醒线程(第二道防线也突破了)。执行完临界区的代码后,再次解锁。如下图所示,注意:默认情况下,这个进程有两个额外的线程,先执行线程1。在图中,只有线程1和线程2分别被执行一次。
#包含stdio.h
#include pthread.h
pthread_mutex_t互斥体;//互斥体
pthread _ cond _ t cond//条件变量
void *thread1(void *arg){
while (1) {
printf(thread1正在运行\ n );
pthread_mutex_lock(互斥);//锁定
pthread_cond_wait( cond,mutex);//等待时挂起,然后解锁。唤醒时,先锁定,再唤醒(即执行下面的代码)。
printf(thread1应用了条件\ n );
pthread_mutex_unlock(互斥);//解锁
睡眠(4);
}
}
void *thread2(void *arg){
while (1) {
printf(线程2正在运行\ n’);
pthread_mutex_lock(互斥);//加锁
pthread_cond_wait( cond,mutex);//等待时挂起,然后开锁,被唤醒时,先加锁,然后再唤醒(即执行下方代码)。
printf(线程2应用了条件\ n’);
pthread _ mutex _解锁(互斥);//开锁
睡眠(2);
}
}
int main(){
pthread_t thid1,thid2
printf(条件变量研究!\ n’);
pthread_mutex_init( mutex,NULL);//互斥量初始化
pthread_cond_init( cond,NULL);//条件变量初始化
pthread_create( thid1,NULL,(void *)thread1,NULL);//线程一创建
pthread_create( thid2,NULL,(void *)thread2,NULL);//线程2创建
做{
pthread _ cond _ signal(cond);//唤醒一个等待线程
睡眠(1);
} while(1);
返回0;
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。