多线程编程

线程是任务调度和执行的基本单位

为什么会有线程

程实现多任务的缺点
进程间切换的计算机资源开销很大,切换效率很低;进程间数据及共享额开销很大

线程和进程的关系

线程是进程的一个执行单元,是进程内的调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程
同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间
进程退出,进程中所有线程全部退出
一个进程崩溃后,不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮
线程不可能完全替代进程
线程拥有独立的属性:独立的ID(TID),独立的切换状态,调度优先级,独立函数栈等等

线程的特点

线程切换的开销很低——实质是函数的切换
线程通信机制简单——全局变量

线程操作

注意:线程函数不是OS提供,而是线程库而是线程库libpthread.a/.so,但是线程的核心实现是离不开OS支持的
线程创建
API:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

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

voi * thread1(void *arg)
{
   while(1)
   {
      printf("hello world!\n");
      sleep(1);
    }
}
int main()
{
   pthread_t id;
   if(pthread_create(&id,NULL,thread1,NULL)!=0)
   {
      perror("pthread create error!\n")
      exit(1);
   }
   pause();
   return 0;
}

线程退出

被动退出
API:int pthread_cancel(pthread_t thread);
必须要有系统调用
主动退出
int pthread_exit(void *retval); 弹栈
如果返回值很多时,就封装成一个结构体,返回结构体变量的地址即可。
return 返回 ;不弹栈
线程等待

目的

保证线程的退出顺序:保证一个线程退出并且回收资源后允许下一个进程退出
回收线程退出时的资源情况:保证当前线程退出后,创建的新线程不会复用刚才退出线程的地址空间
获得新线程退出时的结果是否正确的退出返回值,这个有点类似回收僵尸进程的wait,保证不会发生内存泄露等问题
API:int pthread_join(pthread_t thread, void **retval);
线程状态
可结合态:这种状态下的线程是能够被其他进程回收其资源或杀死的
分离态:这种状态下的线程是不能够被其他线程回收或杀死的;它的存储资源在它终止时由系统自动释放
默认情况下,线程被创建成可结合态

线程同步
线程VS进程
进程:进程空间天然是独立的,因此进程间资源的保护是天然的(现成的),需要重点关心的进程间的通信
线程:多线程天然的共享进程空间,因此线程数据共享是天然的(现成的),需要重点关心的是资源的保护

互斥锁(必须设置为全局变量)
定义一个互斥锁(pthread_mutex_t mutex)
初始化互斥锁(pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER)
加锁解锁(阻塞加锁,非阻塞加锁,访问临界区解锁)
进程退出时销毁互斥锁(删除互斥锁相关的数据,释放互斥锁数据所占用的各种内存资源。)
线程信号量
定义信号量结合(sem_t sem[n],线程信号量集合其实就是一个数组,数组每个元素就是一个信号量。)
初始化集合中的每个信号量,int sem_init(sem_t *sem, int pshared, unsigned int value);
p、v操作( int sem_wait(sem_t *sem)//阻塞p操作;int sem_post(sem_t *sem))
进程结束时,删除线程信号量集合( int sem_destroy(sem_t *sem);)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<semaphore.h>

struct  message
{
    int fd;
};

sem_t sem[1];
void * thread1(void *arg)
{
    struct message msg =  *((struct message * )arg);
    int fd= msg.fd;
    while(1)
    {
        sem_wait(&sem[0]);
        write(fd,"111\n",4);
        sem_post(&sem[0]);
    }
}
void * thread2(void *arg)
{
     struct message msg =  *((struct message * )arg);
    int fd= msg.fd;
    while(1)
    {
        sem_wait(&sem[0]);
        write(fd,"222\n",4);
        sem_post(&sem[0]);
    }
}
void *thread3(void *arg)
{
     struct message msg =  *((struct message * )arg);
    int fd= msg.fd;
    while(1)
    {
        sem_wait(&sem[0]);
        write(fd,"333\n",4);
        sem_post(&sem[0]);
    }
}

int main()
{
    pthread_t id1;
    pthread_t id2;
    pthread_t id3;
    struct message msg;

    int fd;
    fd=open("./a.txt",O_RDWR | O_CREAT | O_APPEND,0644);
    if(fd<0)
    {
        perror("open file error!");
        exit(1);
    }
    msg.fd=fd;
    sem_init(&sem[0],0,1);

     
    if(pthread_create(&id1,NULL,thread1,(void *)(&msg)) != 0)
    {
        perror("thread create error!\n");
        exit(1);
    }
    if(pthread_create(&id2,NULL,thread2,(void *)(&msg)) != 0)
    {
        perror("thread create error!\n");
        exit(1);
    }
   if(pthread_create(&id3,NULL,thread3,(void *)(&msg)) != 0)
    {
        perror("thread create error!\n");
        exit(1);
    }
    pthread_join(id1,NULL);
    pthread_join(id2,NULL);
    pthread_join(id3,NULL);

    return 0;
}


条件变量

多线程配合工作时,当线程检测到某条件不满足时就休眠,直到别的线程将条件准备好,然后通过条件变量将其唤醒。
条件变量需要在互斥锁的配合下才能工作

定义一个条件变量(全局变量)由于条件变量需要互斥锁的配合,所以还需要定义一个线程互斥锁(pthread_cond_t)
初始化条件变量(int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);)
使用条件变量( int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); )
删除条件变量,也需要把互斥锁删除(int pthread_cond_destroy(pthread_cond_t *cond);)

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

int count = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;

void * add_1(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        count++;
        if(count == 5)
        {
            pthread_cond_signal(&cond);
        }
        sleep(1);
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
}
void * print_1(void * arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(count!=5)
        {
            pthread_cond_wait(&cond,&mutex);
        }
        printf("count = %d\n",count);
        count =0;
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
}
int main()
{
    pthread_t id1;
    pthread_t id2;
    int ret;
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);
    ret=pthread_create(&id1,NULL,add_1,NULL);
    if(ret!=0)
    {
        perror("thread creare error!");
        exit(1);
    }
    ret=pthread_create(&id2,NULL,print_1,NULL);
    if(ret!=0)
    {
        perror("thread creare error!");
        exit(1);
    }
    pthread_join(id1,NULL);
    pthread_join(id2,NULL);

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值