线程

线程是进程内部的一个执行单元,是CPU调度的最小单位。

线程是一个轻量级的进程,用来实现多任务并发。

线程是操作系统任务调度的最小单位。

线程由某个进程创建

  1. 线程的创建

    线程由所在进程创建,创建时,进程为其分配独立的栈区空间(默认8M)。

    同一个进程中的线程,共用所在进程的堆区、数据区、文本区。

  2. 线程的调度

    宏观并行

    微观串行

  3. 线程消亡

    线程退出

    回收线程的资源空间

pthread_create

 POSIX 线程库中创建新线程的核心函数。

参数 类型 方向 说明
thread pthread_t * 输出 存储新线程的ID
attr const pthread_attr_t * 输入 线程属性,NULL=默认
start_routine void *(*)(void*) 输入 线程要执行的函数
arg void * 输入 传递给线程函数的参数

传入int型

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

void *thread_func(void *arg) {
    int num = *(int *)arg;  // 取出 int 值
    printf("收到的整数: %d\n", num);
    return NULL;
}

int main() {
    pthread_t tid;
    int value = 100;
    
    // 传入 int 变量的地址
    pthread_create(&tid, NULL, thread_func, &value);
    pthread_join(tid, NULL);
    
    return 0;
}

传入结构体

typedef struct task
{
    pthread_t tid;// 成员1:线程ID
    void *(*pfun)(void*);// 成员2:线程函数指针
}task_t;

/*task_t tasks[]=
{
    {0, main_ctl_task},
    {0, get_usr_cmd_task},
    {0, exec_usr_cmd_task},
    {0, get_pic_task},
    {0, send_pic_task}

};*/
task_t tasks[]=
{
    {.pfun=main_ctl_task},
    {.pfun=get_usr_cmd_task},
    {.pfun=exec_usr_cmd_task},
    {.pfun=get_pic_task},
    {.pfun=send_pic_task}
};//局部定义

int main(void)
{
    create_thread_tasks(tasks,sizeof(tasks)/sizeof(tasks[0]));
    destory_thread_tasks(tasks,sizeof(tasks)/sizeof(tasks[0]));
    return 0;
}
#include<stdio.h>
#include<unistd.h>
#include"task.h"

int create_thread_tasks(task_t *tasks,int len)
{
    for(int i=0;i<len;i++)
    {
        int ret = pthread_create(&(tasks[i].tid),NULL,tasks[i].pfun,NULL);
//
        if(ret!=0)
        {
            fprintf(stderr,"error\n");
            return -1;
        }
    }
    return 0;
    
}

void destory_thread_tasks(task_t *tasks,int len)
{
    for(int i=0;i<len;i++)
    {
        pthread_join(tasks[i].tid,NULL);
    }

}

易错点

// ❌ 错误
void create() {
    int local = 100;//开到栈上会自动销毁
    pthread_create(&tid, NULL, thread_func, &local);
    // local 在函数返回后销毁,线程可能访问无效内存
}

// ✅ 正确
void create() {
    int *ptr = malloc(sizeof(int));
    *ptr = 100;
    pthread_create(&tid, NULL, thread_func, ptr);
    // 线程负责 free
}

pthread_self

POSIX 线程库中用于获取当前线程ID的函数

void *thread_func(void *arg) {
    // 获取当前线程(子线程)的ID
    pthread_t tid = pthread_self();
    printf("子线程ID: %lx\n", tid);
    return NULL;
}

pthread_join(pthread_t thread, void **retval

 POSIX 线程库中用于等待指定线程结束回收其资源的核心函数。

参数 类型 方向 说明
thread pthread_t 输入 要等待的线程ID
retval void ** 输出 接收线程返回值(可为 NULL
返回值 含义
0 成功
pthread_join(tid, NULL);

线程的分离属性

分离属性 :不需要被其他线程回收的线程,称为具有分离属性的线程,结束时可以被操作系统回收。

非分离属性:可以被其他线程回收或者结束的线程称为非分离属性的线程

​ 默认属性:非分离属性

线程的互斥机制

多线程访问临界资源时,存在资源竞争问题。

临界资源:多个线程可以同时操作的资源,比如:全局变量,共享内存等。

如何解决资源竞争问题:

线程的互斥机制:让多个线程在访问临界资源时,具有排他性访问的特性

互斥锁:实现互斥机制

  • 创建互斥锁:pthread_mutex_t
  • 初始化锁:pthread_mutex_init
  • 加锁:pthread_mutex_lock/pthread_mutex_trylock
  • 解锁:pthread_mutex_unlock
  • 销毁锁:pthread_mutex_destroy

注意锁的位置

int atm = 3;

pthread_mutex_t mutex;

void *task(void *arg)
{
	while (1)
	{
		pthread_mutex_lock(&mutex);
		if (atm > 0)
		{
			atm--;
			printf("%lx thread get ATM\n", pthread_self());
			pthread_mutex_unlock(&mutex);
			sleep(rand()%10);
			pthread_mutex_lock(&mutex);
			atm++;
			printf("%lx thread relase ATM\n", pthread_self());
			pthread_mutex_unlock(&mutex);
			return NULL;
		}
		else
		{
			pthread_mutex_unlock(&mutex);	
		}
	}
}

int main(int argc, const char *argv[])
{
	pthread_t tid[10];

	pthread_mutex_init(&mutex, NULL);
	for (int i = 0; i < 10; i++)
	{
		pthread_create(&tid[i], NULL, task, NULL);
	}
	for (int i = 0; i < 10; i++)
	{
		pthread_join(tid[i], NULL);
	}

	pthread_mutex_destroy(&mutex);
	return 0;
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐