线程是CPU调度和分派的基本单位。是比进程更小的能独立运行的基本单位。除了一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),线程基本上不拥有系统资源,但可与同属一个进程的其他线程共享进程所拥有的全部资源。
(1)进程是系统资源分配的最小单位,线程是CPU调度和分派的基本单位。
(2)进程拥有独立的堆栈空间和数据段,每当启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这对于多进程来说十分“奢侈”。线程拥有独立的堆栈空间,但是共享数据段,它们彼此之间使用相同的地址空间,共享大部分数据,比进程更节俭,开销比较小,而且线程彼此间切换的速度比进程更快效率更高。正因为进程有独立的地址空间,所以一个进程崩溃,不会影响其他进程,进程更具有健壮性。而线程只是一个进程中的不同执行路径,一个线程死掉就等于整个进程死掉。
(3)通信机制上,进程间通信相对很复杂,譬如管道,信号,消息队列,共享内存,套接字等通信机制,而线程由于共享数据段所以通信机制很方便。
(4)线程使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
(5)改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
1.phthread_create()
函数用法 | #include int pthread_create(pthread_t *restrict thread, |
函数功能 | 创建线程 参数1,thread:线程ID,用时取地址。&tid。 参数2,attr:线程属性,一般为NULL 参数3,start_routine:线程处理函数,自定义的函数,函数类型为void*,决定该线程要做的动作 参数4,arg:线程处理函数的入参 |
函数返回值 | 线程创建成功返回0,否则返回错误码。 |
2.pthread_join()
函数用法 | #include int pthread_join(pthread_t thread, void **value_ptr); |
函数功能 | 等待线程结束,并回收线程运行时的资源 参数1,thread:线程ID 参数2,value_ptr:存储被等待的线程的返回值 |
函数返回值 | 成功返回0,否则返回错误码。 |
3.pthread_exit()
函数用法 | #include void pthread_exit(void *value_ptr); |
函数功能 | 退出当前线程 参数,value_ptr:存储被退出的线程的返回值 |
函数返回值 | 无返回值 |
4.pthread_cancel()
函数用法 | #include int pthread_cancel(pthread_t thread); |
函数功能 | 取消另一个线程 参数,thread:要被取消的线程的线程ID 通常和pthread_sentcanceltype()配合使用 |
函数返回值 | 成功返回0,否则返回错误码。 |
5.pthread_setcanceltype()
函数用法 | #include int pthread_setcanceltype(int type, int *oldtype); |
函数功能 | 这是当前线程的取消属性 参数1,type:取消类型,有两个选项 PTHREAD_CANCEL_DEFERRED 延迟取消 PTHREAD_CANCEL_ASYNCHRONOUS 立即取消 参数2,oldtyp:保存以前的取消类型。 |
函数返回值 | 成功返回0,否则返回错误码。 |
6.pthread_detach()
函数用法 | #include iint pthread_detach(pthread_t thread); |
函数功能 | 分离当前线程,并且在结束时回收资源 参数,thread:要分离的线程ID 通常和pthread_self()配合使用 |
函数返回值 | 成功返回0,否则返回错误码。 |
7.pthread_self()
函数用法 | #include pthread_t pthread_self(void); |
函数功能 | 返回当前线程ID |
函数返回值 | 返回当前线程ID |
1.线程控制函数的简单运用
#include
#include
#include
pthread_t tid1, tid2;
void delay()
{
int x = 10000;
int y;
while(x > 0)
{
y = 20000;
while(y > 0)
{
y--;
}
x--;
}
}
void *Mypthread1(void * arg)
{
int old;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&old);//设置线程取消属性,立即取消
printf("HelloWorld!\n");
delay();
pthread_exit((void *)100);//线程退出
}
void *Mypthread2(void * arg)
{
printf("%s\n", arg);
pthread_cancel(tid1);//取消线程
//exit(1);//进程退出
}
int main()
{
int ret;
ret = pthread_create(&tid1, NULL, Mypthread1, NULL);//创建线程1
if (ret != 0)
{
perror("pthread_create1");
exit(1);
}
ret = pthread_create(&tid2, NULL, Mypthread2, "HELLOWORLD!");//创建线程2
if (ret != 0)
{
perror("pthread_create2");
exit(1);
}
void *status;
ret = pthread_join(tid1, &status);//两个作用 1、等待 2、回收
if (0 != ret)
{
perror("pthread_join1");
}
printf("Mypthread1 Exit is %d\n", status);
ret = pthread_join(tid2, &status);
if (ret != 0)
{
perror("pthread_join2");
}
return 0;
}
2.之前我们通过用进程来实现使消息队列能发能收,这次使用线程来实现。
msg_send_pthread.c
#include
#include
#include
#include
#include
#include
#include
#define MSGKEY 1234
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[100]; /* message data */
};
pthread_t tid1, tid2;
void *SendData(void *arg)
{
int old;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);//设置线程取消属性为立即取消
int ret;
struct msgbuf mbuf;
int msgid = *(int *)arg;
while (1)
{
memset(mbuf.mtext, 0, sizeof(mbuf.mtext));
scanf("%s", mbuf.mtext);
mbuf.mtype = 1;
ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
if (-1 == ret)
{
perror("msgsnd");
exit(1);
}
if (!strcmp(mbuf.mtext, "bye"))
{
mbuf.mtype = 2;
msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
break;
}
}
}
void *RecvData(void *arg)
{
int ret;
struct msgbuf mbuf;
int msgid = *(int *)arg;
while (1)
{
memset(mbuf.mtext, 0, sizeof(mbuf.mtext));
ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 2,0);
if (-1 == ret)
{
perror("msgrcv");
exit(1);
}
if (!strcmp(mbuf.mtext, "bye"))
{
pthread_cancel(tid1);//取消线程1
break;
}
printf("\t%s\n", mbuf.mtext);
}
}
int main()
{
int ret;
int msgid;
msgid = msgget(MSGKEY, IPC_CREAT | IPC_EXCL); //创建消息队列
if (-1 == msgid)
{
perror("msgget");
exit(1);
}
ret = pthread_create(&tid1, NULL, SendData, &msgid);//创建线程,发送数据
if (ret != 0)
{
perror("pthread_create1");
exit(1);
}
ret = pthread_create(&tid2, NULL, RecvData, &msgid);//创建线程,接收数据
if (ret != 0)
{
perror("pthread_create2");
exit(1);
}
void *status;
ret = pthread_join(tid1, &status);
if (ret != 0)
{
perror("pthread_join1");
}
ret = pthread_join(tid2, &status);
if (ret != 0)
{
perror("pthread_join2");
}
msgctl(msgid, IPC_RMID, NULL);//销毁消息队列
return 0;
}
msg_recv_pthread.c
#include
#include
#include
#include
#include
#include
#include
#define MSGKEY 1234
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[100]; /* message data */
};
pthread_t tid1, tid2;
void *SendData(void *arg)
{
int old;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);//设置线程取消属性为立即取消
int ret;
struct msgbuf mbuf;
int msgid = *(int *)arg;
while (1)
{
memset(mbuf.mtext, 0, sizeof(mbuf.mtext));
scanf("%s", mbuf.mtext);
mbuf.mtype = 2;
ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
if (-1 == ret)
{
perror("msgsnd");
exit(1);
}
if (!strcmp(mbuf.mtext, "bye"))
{
mbuf.mtype = 1;
msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
break;
}
}
}
void *RecvData(void *arg)
{
int ret;
struct msgbuf mbuf;
int msgid = *(int *)arg;
while (1)
{
memset(mbuf.mtext, 0, sizeof(mbuf.mtext));
ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 1,0);
if (-1 == ret)
{
perror("msgrcv");
exit(1);
}
if (!strcmp(mbuf.mtext, "bye"))
{
pthread_cancel(tid1);//取消线程1
break;
}
printf("\t%s\n", mbuf.mtext);
}
}
int main()
{
int ret;
int msgid;
msgid = msgget(MSGKEY, 0); //获取消息队列
if (-1 == msgid)
{
perror("msgget");
exit(1);
}
ret = pthread_create(&tid1, NULL, SendData, &msgid);//创建线程,发送数据
if (ret != 0)
{
perror("pthread_create1");
exit(1);
}
ret = pthread_create(&tid2, NULL, RecvData, &msgid);//创建线程,接收数据
if (ret != 0)
{
perror("pthread_create2");
exit(1);
}
void *status;
ret = pthread_join(tid1, &status);
if (ret != 0)
{
perror("pthread_join1");
}
ret = pthread_join(tid2, &status);
if (ret != 0)
{
perror("pthread_join2");
}
return 0;
}