线程创建以及线程控制

线程底层:

  1. 在linux下PCB模拟实现进程,通俗的说就是一个大的PCB下有很多小的PCB,称为轻量级进程。
  2. 在一个进程中有多个PCB,而这些所有的PCB共用同一份虚拟地址空间。而这些PCB共同基层构成一个PCB组,一个线程组就为一个进程。
    3.一个线程是程序执行的基本单位,进程是资源调度的基本单位。
  3. 线程是CPU调用的基本单位。

线程之间的资源共享 :

独有:

函数调用栈
寄存器 (不是硬件,而是程序运行信息等等)
信号屏蔽字(信号是发给进程的,而一个信号发给一个进程,只要一个线程处理就行) ,errno(防止相互影响), 线程ID, 调度优先级

共享:

共享虚拟地址空间,文件描述符表 ,当前工作路径,用户id,组id,每种信号处理的方式

多进程和多线程用哪一个好

多线程任务的优缺点:
多线程共用进程大部分资源
1.线程间通信更加方便,除了进程通信的方式外还有全局数据/传参等。
2.创建销毁一个现成的成本较进程更加低
3.线程间的调度较于进程更低
缺点:线程之间缺乏访问控制,有些系统调用/异常针对的是整个进程,稳定性比进程的低。例如一个段错误所有进程就挂了。而进程在处理可能发生错误的时候可以用子进程去,子进程挂了父进程还在,还可以处理。

线程控制

1.在linux下操作系统并没有提供线程的控制系统调用接口;因此大佬封装了一套进程库,在linux下在三号手册中。
2.使用库函数实现创建的线程称之为用户态线程,这个用户态线程在内核中使用一个轻量级进程实现调度。
3.linux下的进程:用户态线程+轻量级进程

线程创建

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void * (*start_routine)(void*), void *arg); 

thread: 用于获取线程id :线程地址空间在整个虚拟地址空间中的首地址
attr: 设置线程属性,通常置NULL
start_routine:线程的入口函数(函数运行完毕线程退出)
*arg: 传入参数
返回值:成功返回0,失败返回错误码

当线程创建后可以用:ps-esL 查看线程信息
线程终止:

  1. return不能再主函数中使用,主函数return 会直接退出进程
  2. pthread_exit(void *retval);退出线程自身,谁调用谁退出 retval为返回值
  3. in pthread_cancel(pthread_t thread);取消其他线程,让其他线程退出
    thread 为要取消线程的ID。
    线程退出后,默认不会自动释放资源,(保存自己的退出结果在线程独有的地址空间中)造成资源泄露。
    4.主线程退出后,其他线程照样可以运行
  4. 处于joinable属性的线程必须被等待,否则造成资源泄露
  5. int pthread_join(pthread_t thread,void** val) 等待指定线程退出 val未返回值
// 通过这个就可以明白堆上申请的内存不会被程序释放掉
// return 和 exit 都可以让程序退出
// pthread_cancel(pthread_t tid) 可以让任意线程退出
// pthread_detach(pthread_t tid) 将线程设置datach属性 这时
//  如果进行pthread_join(pthread_t tid, void* ar); 相当于
//  不执行操作
// 一旦主线程退出那么所有线程都退出


#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void* pthread_1(void* agr)
{
  printf("pthread_1 runing 1 \n");
  int* p = (int*)malloc(sizeof(int));
  *p = 1;
  return (void*)p;
}


void* pthread_2(void* arg)
{
  printf("pthread_2 runing 2 tid:%lu \n ", pthread_self());
  long* p = (long*)malloc(sizeof(long)); 
  *p = 1000;
  return (void*)p;
}

void* pthread_3(void* arg)
{
  sleep(1);
  printf("pthread_2 P:%ld", *(long*)arg);
  free(arg);
  while(1)
  {
    printf("pthread_3 ruing \n");
    sleep(1);
  }
  return NULL;
}

void* pthread_4(void* arg)
{
 while(1)
 {
   printf("pthread_4 runing\n");
   sleep(1);
 }
}

void* pthread_5(void* arg)
{

}
int main()
{
  pthread_t tid;
  void* red;

  pthread_create(&tid, NULL, pthread_1, NULL);
  pthread_join(tid, &red);
  printf("pthread_1 exit tid: %lu red: %d\n ", tid , *(int*)red);
  free(red);

  pthread_create(&tid , NULL, pthread_2, NULL);
  pthread_join(tid, &red);
  printf("pthread_2 exit tid: %lu red: %d \n", tid , *(int*)red);

  pthread_create(&tid, NULL, pthread_3, (void*)red);
  sleep(5);
  pthread_cancel(tid);
  pthread_join(tid, NULL);
  printf("第一阶段完毕");
  pthread_t pthread;

  pthread_create(&tid, NULL, pthread_4, NULL);
 // pthread_create(&pthread, NULL, pthread_5, NULL);
  sleep(4);
  pthread_detach(tid);
  pthread_join(tid, NULL);
  printf("------------------主线程退出\n ");
  sleep(5);
  return 0;
}

在这里插入图片描述
线程1和线程2分别是exit和return退出, 两者功能相同, 并且程序员在堆上开辟的内存线程不会释放在线程3中还可以访问
处于detach属性的线程, join不会被阻塞, 直接会运行下面的代码
在主线程打印完 “主线程退出” 这句话后主线程陷入休眠5秒, 之后再退出, 之后主线程退出程序结束, 这样就证明不管其他线程有没有运行完, 整个进程直接退出

死锁代码演示

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t m;

void *runodd(void *d)
{
        int i=0;

        for(i=1;;i+=2)
        {
                pthread_mutex_lock(&m);
                printf("奇数:%d\n",i);
                usleep(100);
                pthread_mutex_unlock(&m);
        }
}

void *runeven(void *d)
{
        int i=0;
        for(i=0;;i+=2)
        {
                pthread_mutex_lock(&m);
                printf("偶数:%d\n",i);
                usleep(100);
                pthread_mutex_unlock(&m);
        }
}
int main()
{
        pthread_t todd,teven;
        pthread_mutex_init(&m,0);
        pthread_create(&todd,0,runodd,0);
        pthread_create(&teven,0,runeven,0);
        sleep(1);

        printf("外部强制停止todd线程\n");
        
        pthread_cancel(todd); /*给线程发送退出信号,当遇到取消点的时候,进程就会退出
                                使用某些函数就会出现取消点 例如:sleep,wait,waitpid,waitid,send等函数 */

        pthread_join(todd,(void**)0);
        pthread_join(teven,(void**)0);
        pthread_mutex_destroy(&m);
        return 0;
}

上述代码在线程运行todd函数的时候由于在sleep处退出了,而此时退出并没有把锁打开,这样一来运行runeven函数的线程就加不上锁而等待,而主线程此时又在等它退出,从而形成死锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值