1、 多进程的优点:
可以执行多任务,进程之间切换频繁时,CPU效率比较低,进程间通信较复杂
多线程(同一个进程里面的多线程)
多线程可以实现多任务,并且通信较为简单
2、
不同的进程地址空间是独立的
同一个进程的不同线程共享地址空间(堆段、数据段、代码段),栈段是独立的
原来的进程可以创建一个新的线程,把原来的进程称为是主线程,新创建的线程称为是子线程
3、进程和线程的区别和联系
进程和线程都是动态的
进程和线程都可以实现并发任务
进程是分配资源的最小单位
线程是调度的最小单位
4、创建线程
int pthread_create(pthread_ * threadID, const pehread_attr_t *attr, void * (* routine)(void *),void * arg);
功能:创建线程
参数:threadID:线程的编号
attr:线程属性,一般写成NULL
routine:函数指针,是线程执行函数
arg:传递给线程执行的函数的参数
返回值:成功为0,失败为-1
在编译线程相关的函数时,需要在gcc后面链接pthread库,例:gcc thread.c -lpthread
#include <stdio.h>
#include <pthread.h>
void * threadFunc(void * arg)
{
printf("thread do something\r\n");
}
int main()
{
pthread_t threadId;
int ret = 0;
ret = pthread_create(&threadId, NULL, threadFunc, NULL);
if (ret < 0)
{
perror("create thread error");
return -1;
}
// while(1)
// {
printf("main thread\r\n");
sleep(1);
// }
return 0;
}
等待子线程退出
int pthread_join(pthread_t threadID, void ** arg);
功能:等待子线程日退出
参数:threadID:要等待的线程的线程编号
arg : 子线程退出的状态
返回值:成功返回0,失败返回-1;
join一般放在主线程即将退出之前
#include <stdio.h>
#include <pthread.h>
void * threadFunc(void * arg)
{
printf("thread do something\r\n");
sleep(3);
}
int main()
{
pthread_t threadId;
int ret = 0;
ret = pthread_create(&threadId, NULL, threadFunc, NULL);
if (ret < 0)
{
perror("create thread error");
return -1;
}
// while(1)
// {
// }
pthread_join(threadId, NULL);
printf("after join\r\n");
return 0;
}
线程退出
void pthread_exit (void * ptr);
功能:线程退出
参数:ptr线程退出时返回的值
注意:局部变量的地址不能返回,因此局部变量的地址不能作为pthread_exit 的参数
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
void * threadFunc(void * arg)
{
//int i = 0;
printf("thread do something\r\n");
sleep(3);
pthread_exit(&i);
//exit(0);
//return &i;
}
int main()
{
pthread_t threadId;
int ret = 0;
ret = pthread_create(&threadId, NULL, threadFunc, NULL);
if (ret < 0)
{
perror("create thread error");
return -1;
}
// while(1)
// {
// }
pthread_join(threadId, NULL);
printf("after join\r\n");
return 0;
}
5、线程间同步
使用semaphore PV原语
同步例如:ABABABABAB 交替执行
1、定义 sem_t sem;
2、初始化 sem_init(&sem , 0 , value); //value是一个非负整数
3、创建线程
4、在线程执行函数中,在合适的位置先进行p操作(减1)sem_wait do someThing, v操作(加1) sem_post(&sem)
5、在线程执行结束前,如果不再使用sem,需要将它销sem_destroy(&sem)
注:p操作sem_wait是一个阻塞函数
A线程V操作其他线程的sem
A线程中P-->semA V-->semB
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem1;
sem_t sem2;
void * threadFunc1(void * arg)
{
while(1)
{
sem_wait(&sem1);
printf("hello!\r\n");
// sleep(1);
sem_post(&sem2);
}
}
void * threadFunc2(void * arg)
{
while(1)
{
sem_wait(&sem2);
printf("welcome farsight!\r\n");
// sleep(1);
sem_post(&sem1);
}
}
int main()
{
pthread_t thid1;
pthread_t thid2;
int ret1 = 0;
int ret2 = 0;
sem_init(&sem1, 0, 1);
sem_init(&sem2, 0, 0);
ret1 = pthread_create(&thid1, NULL, threadFunc1, NULL);
ret2 = pthread_create(&thid2, NULL, threadFunc2, NULL);
if (ret1 < 0 || ret2 < 0)
{
perror("create thread error");
return -1;
}
pthread_join(thid1, NULL);
pthread_join(thid2, NULL);
sem_destroy(&sem1);
sem_destroy(&sem2);
return 0;
}
6、线程互斥
mutex 保证线程执行的完整性
锁的分类(了解)
快速互斥锁
读写锁(银行)
条件锁
mutex使用(保证线程执行的完整性)
1、创建/定义mutex pthread_mutex_t mutex;
2、初始化锁 pthread_mutex_init(&mutex , NULL);
3、创建线程 pthread_create(&threadID, NULL, threadFunc, NULL);
4、在线程执行函数中,在合适的位置先上锁 pthread_mutex_lock(&mutex)
再执行功能do something,最后解锁 pthread_mutex_unlock(&mutex);
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex;
void * threadFunc(void * arg)
{
static char data[11] = {};
int i = 0;
char * p = (char * )arg;
pthread_mutex_lock(&mutex);
for (i = 0; i < 10; i++)
{
data[i] = p[i];
sleep(1);
}
pthread_mutex_unlock(&mutex);
printf("data=%s\n", data);
}
int main()
{
char buf1[] = {"1234567890"};
char buf2[] = {"abcdefghig"};
pthread_t thid1;
pthread_t thid2;
int ret1 = -1;
int ret2 = -1;
pthread_mutex_init(&mutex, NULL);
//create thread, and copy buf to own dataBuf
ret1 = pthread_create(&thid1, NULL, threadFunc, buf1);
ret2 = pthread_create(&thid2, NULL, threadFunc, buf2);
if (ret1 < 0 || ret2 < 0)
{
perror("pthread create error");
return -1;
}
pthread_join(thid1, NULL);
pthread_join(thid2, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
5、线程执行结束,不再使用锁时,需要销毁锁
pthread_mutex_destroy(&mutex);
注:上锁 pthread_mutex_lock(&mutex)是阻塞函数
A线程上锁,只能由A线程进行解锁,其它线程没有权限解这个锁
可重入---每次执行都一样 不可重入---执行可能不一样
动态定义宏的方法
在编译的时候,给gcc加一个参数 -DXXXX 这里的XXXX是具体代码中用到的宏名