Linux线程

1.进程与线程的区别

答:一个程序的运行叫做进程,线程是进程的容器。一个进程在运行时,系统会给他分配内存,维护他的数据段,代码段、堆、栈等等,而线程会共享进程这些资源。 

一个进程同一时刻只做一件事,有了线程后,可以把进程设计成在同一时刻做多件事。 

进程有独立的地址空间,进程崩溃后,不会对其他进程造成影响。线程没有独立的地址空间,线程死掉就等于进程死掉。

进程切换时,消耗资源大,效率差。

2.为什么要使用线程

线程是“节俭”的多任务操作模式:从开销方面来讲,线程的开销比较节省。每个线程的切换速度比较快。

线程的通信很方便。对于不同进程来讲,它们有独立的数据空间,要进行数据传递只能通过通信的方式如管道,消息队列,共享内存等等。线程共享的是数据空间,一个线程的数据可以给其他线程使用,这比较方便快捷。

3.线程

(1)线程创建

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// 返回:若成功返回0,否则返回错误编号

        当pthread_create成功返回时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,暂可以把它设置为NULL,以创建默认属性的线程。

  新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg。如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。

 (2)线程退出

#include <pthread.h>
int pthread_exit(void *rval_ptr);

        rval_ptr是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。

 (3)线程等待

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号

如果对线程的返回值不感兴趣,可以把rval_ptr置为NULL。在这种情况下,调用pthread_join函数将等待指定的线程终止,但并不获得线程的终止状态。

(4)线程ID获取

#include <pthread.h>
pthread_t pthread_self(void);
// 返回:调用线程的ID

例子1

#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
}

int main()
{
        int ret;
        int param = 100;
        pthread_t t1;

        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        if(ret==0){
                printf("pthread creat ok\n");
        }
        printf("main:%ld \n",(unsigned long)pthread_self());
         //pthread_self()获取线程ID
        //while(1);
        pthread_join(t1,NULL);
        return 0;
}

 运行结果:

pthread creat ok
main:140192978982656 
t1:140192970696448 thread is create
param is 100

例子2

#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{
        static int ret = 10 ;
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);

        pthread_exit((void *)&ret);
}

int main()
{
        int ret;
        int param = 100;
        pthread_t t1;
        int *pret;

        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        if(ret==0){
                printf("pthread creat ok\n");
        }
        printf("main:%ld \n",(unsigned long)pthread_self());

        pthread_join(t1,(void **)&pret);
        printf("main:ti quit %d \n",*pret);
        return 0;
}

 例子2实现了主线程等待时实现接收线程返回的值。

 结果:

pthread creat ok
main:140672702207744 
t1:140672693921536 thread is create
param is 100
main:ti quit 10 

 例子3

#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{
        static char *p="t1 run";
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);

        pthread_exit((void *)p);
}

int main()
{
        int ret;
        int param = 100;
        pthread_t t1;
        char *pret;

        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        if(ret==0){
                printf("pthread creat ok\n");
        }
        printf("main:%ld \n",(unsigned long)pthread_self());

//      while(1);
        pthread_join(t1,(void **)&pret);
        printf("main:ti quit %s \n",pret);
        return 0;
}

当然返回字符串也可以

结果:

pthread creat ok
main:140689130268416 
t1:140689121982208 thread is create
param is 100
main:ti quit t1 run  

例子4

#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;
void *func1(void *arg)
{
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        while(1){
        printf("t1:%d\n",g_data++);
        sleep(1);

        if(g_data==7){
                pthread_exit(NULL);
        }

        }
}
void *func2(void *arg)
{
        printf("t2::%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        while(1){
        printf("t2:%d\n",g_data++);
        sleep(1);
        }
}
int main()
{
        int ret;
        int param = 100;
        pthread_t t1;
        pthread_t t2;

        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        ret=pthread_create(&t2,NULL,func2,(void *)&param);
        if(ret==0){
                printf("pthread creat ok\n");
        }
        printf("main:%ld \n",(unsigned long)pthread_self());

        while(1){
        printf("main:%d\n",g_data++);
        sleep(1);
        }
        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        return 0;
}

两个线程验证同一进程下, 同一时刻做不止一件事,每个线程各自处理独立的任务。

结果:

 4.互斥锁

(1)创建及销毁互斥锁

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
// 返回:若成功返回0,否则返回错误编号

 要用默认的属性初始化互斥量,只需把attr设置为NULL。 

(2) 加锁及解锁

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
// 返回:若成功返回0,否则返回错误编号

 例子5

#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex;
void *func1(void *arg)
{
        int i;
        pthread_mutex_lock(&mutex);
        for(i=0;i<5;i++){
                printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
                printf("param is %d\n",*(int *)arg);
                sleep(1);
        }

        pthread_mutex_unlock(&mutex);
}
void *func2(void *arg)
{
        pthread_mutex_lock(&mutex);
        printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        pthread_mutex_unlock(&mutex);
}
void *func3(void *arg)
{
        pthread_mutex_lock(&mutex);
        printf("t3:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        pthread_mutex_unlock(&mutex);
}
int main()
{
        int ret;
        int param = 100;
        pthread_t t1;
        pthread_t t2;
        pthread_t t3;
        pthread_mutex_init(&mutex,NULL);
        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        ret=pthread_create(&t2,NULL,func2,(void *)&param);
        ret=pthread_create(&t3,NULL,func3,(void *)&param);
        if(ret==0){
                printf("pthread creat ok\n");
        }
        printf("main:%ld \n",(unsigned long)pthread_self());

        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        pthread_join(t3,NULL);
        pthread_mutex_destroy(&mutex);
        return 0;
}

该代码为互斥锁的实现,哪个线程先运行是随机的,假如func1先运行,那么锁住的代码会先执行完毕才会执行其他线程代码。

 例子6

#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;
pthread_mutex_t mutex;
void *func1(void *arg)
{
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        pthread_mutex_lock(&mutex);
        while(1){
        printf("t1:%d\n",g_data++);
        sleep(1);

        if(g_data==3){
                pthread_mutex_unlock(&mutex);
                printf("====================\n");
//              pthread_exit(NULL);
                exit(0);
        }

        }
}
void *func2(void *arg)
{
        printf("t2::%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        while(1){
        printf("t2:%d\n",g_data);
        pthread_mutex_lock(&mutex);
        g_data++;
        pthread_mutex_unlock(&mutex);
        sleep(1);
        }
}
int main()
{
        int ret;
        int param = 100;
        pthread_t t1;
        pthread_t t2;
        pthread_mutex_init(&mutex,NULL);

        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        ret=pthread_create(&t2,NULL,func2,(void *)&param);
        if(ret==0){
                printf("pthread creat ok\n");
        }
        printf("main:%ld \n",(unsigned long)pthread_self());

        while(1){
        printf("main:%d\n",g_data);
        sleep(1);
        }
        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        pthread_mutex_destroy(&mutex);
    

 通过锁的方式验证线程退出而导致进程退出。

结果:

例子7

#include <stdio.h>
#include <pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
void *func1(void *arg)
{
        int i;
        pthread_mutex_lock(&mutex);
        sleep(1);
        pthread_mutex_lock(&mutex2);
        for(i=0;i<5;i++){
                printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
                printf("param is %d\n",*(int *)arg);
                sleep(1);
        }

        pthread_mutex_unlock(&mutex);
}
void *func2(void *arg)
{
        pthread_mutex_lock(&mutex2);
        sleep(1);
        pthread_mutex_lock(&mutex);
        printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        pthread_mutex_unlock(&mutex);
}
void *func3(void *arg)
{
        pthread_mutex_lock(&mutex);
        printf("t3:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        pthread_mutex_unlock(&mutex);
}
int main()
{
        int ret;
        int param = 100;
        pthread_t t1;
        pthread_t t2;
        pthread_t t3;
        pthread_mutex_init(&mutex,NULL);
        pthread_mutex_init(&mutex2,NULL);
        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        ret=pthread_create(&t2,NULL,func2,(void *)&param);
        ret=pthread_create(&t3,NULL,func3,(void *)&param);
        if(ret==0){
                printf("pthread creat ok\n");
        }
        printf("main:%ld \n",(unsigned long)pthread_self());

        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        pthread_join(t3,NULL);
        pthread_mutex_destroy(&mutex);
        pthread_mutex_destroy(&mutex2);
        return 0;
}

 死锁代码。死锁的意思是两把锁,线程A握着第一把锁想去拿第二把锁,线程B握着第二把锁想去拿第一把锁,谁也不让谁,导致程序阻塞。

结果:

5.与条件变量相关API 

 (1)创建及销毁条件变量

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
// 返回:若成功返回0,否则返回错误编号

  除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。

2)等待

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
// 返回:若成功返回0,否则返回错误编号

pthread_cond_wait等待条件变为真。如果在给定的时间内条件不能满足,那么会一直阻塞等待。

(3)触发

#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
// 返回:若成功返回0,否则返回错误编号

  这两个函数可以用于通知线程条件已经满足。pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast函数将唤醒等待该条件的所有进程。

注意一定要在改变条件状态以后再给线程发信号。

例子8

#include <stdio.h>
#include <pthread.h>
int g_data=0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *func1(void *arg)
{
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        while(1){
        pthread_cond_wait(&cond,&mutex);
                printf("====================\n");

        printf("t1:%d\n",g_data++);
        g_data=0;
        sleep(1);

        }
}
void *func2(void *arg)
{
        printf("t2::%ld thread is create\n",(unsigned long)pthread_self());
        printf("param is %d\n",*(int *)arg);
        while(1){
        printf("t2:%d\n",g_data);
        pthread_mutex_lock(&mutex);
        g_data++;
        if(g_data==3){
                pthread_cond_signal(&cond);
        }
        pthread_mutex_unlock(&mutex);
        sleep(1);
        }
}
int main()
{
        int ret;
        int param = 100;
        pthread_t t1;
        pthread_t t2;
        pthread_mutex_init(&mutex,NULL);
        pthread_cond_init(&cond,NULL);

        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        ret=pthread_create(&t2,NULL,func2,(void *)&param);

        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);
        return 0;
}

 该代码利用条件变量等待func2的data==3时,执行pthread_cond_signal语句,func1的pthread_cond_wait才能执行下去。

结果:

参考:linux多线程初探 

学习笔记,仅供参考 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中的多线程实际上是通过进程来模拟实现的。在Linux中,多个线程是通过共享父进程的资源来实现的,而不是像其他操作系统那样拥有自己独立的线程管理模块。因此,在Linux中所谓的“线程”其实是通过克隆父进程的资源而形成的“线程”。这也是为什么在Linux中所说的“线程”概念需要加上引号的原因。 对于Linux中的线程,需要使用线程库来进行管理。具体来说,Linux中的线程ID(pthread_t类型)实质上是进程地址空间上的一个地址。因此,要管理这些线程,需要在线程库中进行描述和组织。 由于Linux中没有真正意义上的线程,因此线程的管理和调度都是由线程库来完成的。线程库负责创建线程、终止线程、调度线程、切换线程,以及为线程分配资源、释放资源和回收资源等任务。需要注意的是,线程的具体实现取决于Linux的实现,目前Linux使用的是NPTL(Native POSIX Thread Library)。 总结来说,Linux中的多线程是通过进程来模拟实现的,线程共享父进程的资源。线程的管理和调度由线程库完成。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux —— 多线程](https://blog.csdn.net/sjsjnsjnn/article/details/126062127)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值