嵌入式系统设计——多线程编程(8)

线程概述:

(1)线程是任务调度和执行的基本单位。
(2)为什么会有线程?
A-进程实现多任务的缺点:
a.进程间切换的计算机资源开销很大,切换效率非常低。
b.进程间数据共享的开销也很大。

B-线程和进程的关系
1.线程是进程的一个执行单元,是进程内的调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程
2.同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间
3.进程退出,进程中所有线程全部退出
4.一个进程崩溃后,不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮
5.线程不可能完全替代进程
6.线程拥有独立的属性:独立的ID(TID),独立的切换状态,调度优先级,独立函数栈等等
(3)线程的特点:
①线程切换的开销很低(实质是函数的切换);
②线程通信机制简单(全局变量)。

多线程的实现

——注意:线程函数不是OS提供,而是线程库而是线程库libpthread.a/.so,但是线程的核心实现是离不开OS支持的
线程控制函数有: pthread_create、pthread_join、pthread_detach、pthread_cancel、pthread_ exit等。
线程库和函数手册的安装
sudo apt-get install glibc-doc
安装线程库
sudo apt get install manpages posix dev: 安装线程库的函数手册
线程创建
代码实例:创建两个次线程,主线程和两个次线程一起的向同一个文件中写"hello”“world\n”
API:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

#include 
#include 
#include 

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);
    线程状态
  • 可结合态:这种状态下的线程是能够被其他进程回收其资源或杀死的;
  • 分离态:这种状态下的线程是不能够被其他线程回收或杀死的:它的存储资源在它终止时由系统自动释放;
    ——默认情况下,线程被创建成可结合态
    如何避免多线程退出导致的内存泄漏?

每个可结合线程需要显示的调用pthread_join回收
将其变成分离态的线程;线程分离函数–pthread_ detach

线程同步机制

线程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
#include
#include
#include
#include
#include
#include
#include
#include

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
#include
#include

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;
}

你可能感兴趣的:(嵌入式系统设计——多线程编程(8))