Linux下多线程机制

作者:华清远见

1 线程不能独立运行,要依附于进程

2 如果创建一个子线程只需要重新分配栈空间

3 多个线程可以并行运行

4 线程之间可以有共同的全局变量(全局区,任何线程都可以访问)

5 多线程效率高

如何创建子线程(在进程中创建线程)

#include

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

功能:创建一个子线程

参数:

thread [出参],当程序执行此函数,此函数会传出一个值,线程的id

attr [入参],通常为NULL, 线程的属性,如果为NULL, 属性默认(线程优先级,线程堆栈大小....)

start_routine 函数指针,需要传进来一个函数名,然后会自动执行此函数,

此函数就是线程需要执行的程序

arg 此参数专门给第三个参数start_routine使用的,此参数,作为start_routine函数的参数

int process(int (*p)(int, int), int a, int b)

{

p(a, b);

}

创建一个线程实例:

#include

#include

void *fun(void *p)

{

while(1)

{

printf("thread 1 running\n");

sleep(1);

}

}

int main()

{

pthread_t id;

pthread_create(&id, NULL, fun, NULL);

printf("%lu\n", id);

while(1) //目的:让主进程不结束

{

;

}

}

编译时: gcc -o hello hello.c -lpthread //多线程是一个第三库函数,所以要加-lpthread

多线程的好处:

要实现 1 接收键盘输入 2 同时每隔一秒钟打印一下家中的温度

pthread_join(); ///函数功能:主进程如果执行到此函数,将阻塞,等待子线程结束

#include

#include

void *fun(void *p)

{

while(1)

{

printf("thread 1 running\n");

sleep(1);

}

}

int main()

{

pthread_t id;

pthread_create(&id, NULL, fun, NULL);

printf("%lu\n", id);

pthread_join(id, NULL); //阻塞,等待子线程结束, 节省cpu资源

}

线程参数

//////////////实例:传递字符串给线程/////////////////////

#include

#include

void *fun(void *p)

{

//char *q = (char *)p;

while(1)

{

printf("%s\n", (char *)p);

sleep(1);

}

}

int main()

{

char s[] = "hello world";

pthread_t id;

pthread_create(&id, NULL, fun, s);

printf("%lu\n", id);

pthread_join(id, NULL); //阻塞,等待子线程结束, 节省cpu资源

}

//////////////实例:传递整形变量给线程/////////////////////

#include

#include

void *fun(void *p)

{

int *q = (int *)p;

while(1)

{

printf("%d\n", *q);

sleep(1);

}

}

int main()

{

int a = 100;

pthread_t id;

pthread_create(&id, NULL, fun, &a);

printf("%lu\n", id);

pthread_join(id, NULL); //阻塞,等待子线程结束, 节省cpu资源

}

void *p ///无类型指针,可以定义变量,但不可以使用(*p = 100, p++, p--)

///无类型指针只能赋值给另一个带类型的指针变量

线程的同步与互斥

同步(按照预想的顺序执行)

M->Y->M->Y->M->Y

M->YYY->M->YYY......

互斥

你用,我不能用(如:网络打印机,A 打印时, B不可以打印)

/////互斥例子

#include

#include

int a[10] = { 0 }; ///共享资源

int i;

void *fun1()

{

while(1)

{

int i;

for(i = 0; i < 10; i++)

{

a[i] = i;

}

sleep(2);

for(i = 0; i < 10; i++)

{

printf("a[%d] is %d\n", i, a[i]);

}

}

}

void *fun2()

{

while(1)

{

sleep(1);

for(i = 0; i < 10; i++)

{

a[i] = 1;

}

}

}

int main()

{

pthread_t id1, id2;

pthread_create(&id1, NULL, fun1, NULL);

pthread_create(&id2, NULL, fun2, NULL);

pthread_join(id1, NULL);

}

//////线程同步(mutex)

A 使用共享资源,加锁,如果这时B也使用共享资源,

B也加锁,但是锁已经被A占用,B只能等,一旦A解锁,B运行,加锁,使用共享资源

//////互斥锁,用来解决共享资源同步的问题,(互斥锁初始化)

pthread_mutex_t 互斥锁类型结构体

1 创建互斥锁(初始化互斥锁)

pthread_mutex_t mutex;

int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr *mutexattr);

mutex [出参] 创建互斥锁,会将新建的互斥锁信息传递给mutex变量

mutexattr 互斥锁属性,默认为NULL

例:

pthread_mutex_init(&mutex, NULL); //创建并初始化互斥锁

2 加锁

一旦某个线程使用共享资源,就加锁

int pthread_mutex_lock(pthread_mutex_t *mutex); //如果加锁不成功(某个线程已经加锁),阻塞

3 解锁

int pthread_mutex_unlock(pthread_mutex_t *mutex); //如果某个线程正在等待加锁,那么这线程进入就绪态

#include

#include

int a[10] = { 0 }; ///共享资源

int i;

pthread_mutex_t mutex;

void *fun1()

{

while(1)

{

int i;

pthread_mutex_lock(&mutex);

for(i = 0; i < 10; i++)

{

a[i] = i;

}

sleep(2);

for(i = 0; i < 10; i++)

{

printf("a[%d] is %d\n", i, a[i]);

}

pthread_mutex_unlock(&mutex);

sleep(1);

}

}

void *fun2()

{

while(1)

{

sleep(1);

pthread_mutex_lock(&mutex);

for(i = 0; i < 10; i++)

{

a[i] = 1;

}

pthread_mutex_unlock(&mutex);

}

}

int main()

{

pthread_t id1, id2;

pthread_mutex_init(&mutex, NULL);

pthread_create(&id1, NULL, fun1, NULL);

pthread_create(&id2, NULL, fun2, NULL);

pthread_join(id1, NULL);

}

////////信号量 (semaphore 简写 sem)

同样可以解决共享资源互斥和同步的问题

信号量可以控制多个共享资源被访问互斥的问题

#include

sem_t sem;

1 创建信号量(初始化信号量)

int sem_init(sem_t *sem, int pshared, int value);

sem [出参], 在创建信号量时,传出的信号量结构体

pshared 通常写0,代表此信号量在多线程之间使用

value 共享资源个数

sem_init(&sem, 0, 3);

sem_init(&sem, 0, 1);

sem_init(&sem, 0, 0);

2 请求信号量

sem_wait(&sem); //如果共享资源个数不为0, 请求成功,使用共享资源,然后共享资源个数-1

//当共享资源个数为0时,请求失败,阻塞

3 释放信号量

sem_post(&sem); //释放信号量,如果有线程正在阻塞等待信号量,那么阻塞解除,

//如果没有线程正在等待信号量,共享资源个数+1

四个线程共享信号量实例

sem_init(&sem, 0, 3); //表示共享资源个数有三个

线程A 调用sem_wait(&sem); //共享资源个数-1, 2

线程B 调用sem_wait(&sem); //共享资源个数-1, 1

线程C 调用sem_wait(&sem); //共享资源个数-1, 0

线程D 调用sem_wait(&sem); //共享资源个数已经为0, 线程D阻塞

如果线程A 调用sem_post(&sem); //线程D 解除阻塞

线程属性

线程可以设置堆栈大小,可以设置线程优先级

默认情况堆栈大小(有些系统1M, 有些2M, 有些4M, 有些8M)

如果定义一个局部变量占用空间特别大,要改堆栈大小

测试线程堆栈大小

#include

#include

void *fun()

{

int a[1000000]; //约等于 4M 1M 1024k 1k 1024B

while(1)

{

printf("thread 1\n");

sleep(1);

}

}

int main()

{

pthread_t id1;

pthread_create(&id1, NULL, fun, NULL);

pthread_join(id1, NULL);

}

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

第二个参数 pthread_attr_t *attr; 线程属性,默认NULL

1 获得线程默认属性,赋值给attr

pthread_attr_t attr;

pthread_attr_init(&attr); // 功能:获取线程的默认属性,会更改attr的值,给一个默认值

2 设置线程的堆栈大小属性

pthread_attr_setstacksize(&attr, 14000000); ///功能:设置堆栈大小属性

#include

#include

void *fun()

{

int a[1000000]; //约等于 4M 1M 1024k 1k 1024B

while(1)

{

printf("thread 1\n");

sleep(1);

}

}

int main()

{

pthread_t id1;

pthread_attr_t attr;

pthread_attr_init(&attr); // 功能:获取线程的默认属性,会更改attr的值,给一个默认值

pthread_attr_setstacksize(&attr, 14000000); ///功能:设置堆栈大小属性

pthread_create(&id1, &attr, fun, NULL);

pthread_join(id1, NULL);

}

你可能感兴趣的:(linux嵌入式方向)