线程管理 - d15¶
一、基本概念¶
- 1.线程就是进程中代码的执行路线,即进程内部的控制序列。
程序――磁盘文件,纸面上的旅行日程表
进程――内存数据,头脑中的旅行计划
线程――执行路径,按照计划旅行
- 2.线程只是一个执行路径,并不拥有独立的内存资源,
共享进程的代码区、数据区、堆区、命令行参数和环境变量。
- 3.线程拥有自己独立的栈,因此用户自己独立的局部变量。
- 4.一个进程可以同时拥有多个线程,但是至少有一个主线程。
二、POSIX线程¶
IEEE POSIX 1003.1c指定了POSIX线程标准。
// pthread
#include <pthread.h>
# libpthread.so
gcc ... -lpthread
三、POSIX线程库的功能¶
- 1.线程管理:创建、销毁、分离、汇合、获取或者设置属性。
- 2.线程同步:解决并发冲突问题。
四、线程函数¶
1.创建(工作)线程¶
int pthread_create (
pthread_t* tid, // 线程ID
const pthread_attr_t* attr, // 线程属性,置NULL表示缺省属性
void* (*start_routine) (void*), // 线程过程函数
void* arg // 传递给线程过程函数的参数
);
/* 内核:开辟一个新的线程,在该线程中调用
start_routine (arg);
*/
// 成功返回0,失败返回错误码。
2.汇合线程¶
int pthread_join (
pthread_t tid, // 所要汇合的线程ID
void** retval // 线程过程函数的返回值
);
// 线程版的waitpid。
// 该函数会一直阻塞,直到tid参数所标识的线程结束(线程过程函数返回),成功返回0,失败返回错误码。
// 如果对线程过程函数的返回值不感兴趣,retval可以置NULL。
3.获取线程自身的ID¶
pthread_t pthread_self (void);
//成功返回调用线程的ID,不会失败。
4.比较线程ID¶
int pthread_equal (pthread_t t1, pthread_t t2);
// t1和t2相等返回非0,否则返回0。
5.终止线程(线程自杀)¶
void pthread_exit (void* retval);
// 线程版的exit。
/*
void fun2 (void) {
if (我实在受不了了)
exit (-1);
}
void fun1 (void) {
fun2 ();
}
int main (void) {
fun1 ();
return 0;
}
*/
6.分离线程¶
默认情况下的线程都是可汇合线程,即可以通过pthread_join汇合的线程。 这样的线程即便终止,系统仍然会为其保留部分资源(其中包括线程过程函数的返回值),直到调用pthread_join函数,这部分资源才会被回收。
调用如下函数:
pthread_detach (pthread_t tid);
// 将tid参数所标识的线程置为分离线程。这样的线程不可被pthread_join汇合,线程终止以后其全部资源被系统自动回收。
7.取消线程(线程他杀)¶
int pthread_cancel (pthread_t tid);
// 成功返回0,失败返回错误码。
// 设置调用线程的取消状态:
int pthread_setcancelstate (int state, int* oldstate);
/*
state取值:
PTHREAD_CANCEL_ENABLE - 可以取消(默认)
PTHREAD_CANCEL_DISABLE - 禁止取消
*/
// 设置调用线程的取消类型:
int pthread_setcanceltype (int type, int* oldtype);
/*
type取值:
PTHREAD_CANCEL_DEFERRED - 延迟取消(默认)
PTHREAD_CANCEL_ASYNCHRONOUS - 立即取消
*/
网络通信补遗¶
#include <sys/socket.h>
ssize_t recvfrom (int sockfd,
void* buf,
size_t len,
int flags,
struct sockaddr* addr,
socklen_t* addrlen);
// 输入数addr和addrlen表示发送方的地址信息。
ssize_t sendto ( int sockfd,
void* buf,
size_t len,
int flags,
struct sockaddr const* addr,
socklen_t addrlen);
// 输入参数addr和addrlen表示接收方的地址信息。
example¶
/*
* create.c
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
for (;;) {
printf ("%c", (char)arg);
usleep (100000);
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, (void*)'A');
if (error) {
printf ("pthread_create: %s\n", strerror (error));
return -1;
}
printf ("线程ID:%lu\n", tid);
error = pthread_create (&tid, NULL, thread_proc, (void*)'B');
if (error) {
printf ("pthread_create: %s\n", strerror (error));
return -1;
}
printf ("线程ID:%lu\n", tid);
thread_proc ((void*)'C');
//getchar ();
return 0;
}
/*
* join.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PI 3.1415926
double g_s;
void* area (void* arg) {
double r = *(double*)arg;
/*
static double s;
s = PI * r * r;
return &s;
*//*
double* s = malloc (sizeof (double));
*s = PI * r * r;
return s;
*/
g_s = PI * r * r;
return NULL;
}
int main (void) {
double r = 10;
pthread_t tid;
pthread_create (&tid, NULL, area, &r);
/*
double* s;
pthread_join (tid, (void**)&s); // *s = ...
printf ("%g\n", *s);
free (s);
*/
//sleep (1);
pthread_join (tid, NULL);
printf ("%g\n", g_s);
return 0;
}
/*
* exit.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PI 3.1415926
void* area (void* arg) {
double r = *(double*)arg;
double* s = malloc (sizeof (double));
*s = 2 * PI * r;
pthread_exit (s);
*s = PI * r * r;
return s;
}
int main (void) {
//pthread_exit (NULL);
double r = 10;
pthread_t tid;
pthread_create (&tid, NULL, area, &r);
double* s;
pthread_join (tid, (void**)&s); // *s = ...
printf ("%g\n", *s);
free (s);
return 0;
}
/*
* equal.c
*/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
pthread_t g_main;
void* ismain (void* arg) {
if (pthread_equal (pthread_self (), g_main)){
printf ("这是主线程。\n");
}
else{
printf ("这是子线程。\n");
}
return NULL;
}
int main (void)
{
g_main = pthread_self ();
ismain (NULL);
pthread_t tid;
pthread_create (&tid, NULL, ismain, NULL);
pthread_join (tid, NULL);
return 0;
}
/*
* detach.c
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
//pthread_detach (pthread_self ());
int i;
for (i = 0; i < 200; ++i) {
putchar ('-');
usleep (50000);
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
pthread_t tid;
pthread_create (&tid, NULL, thread_proc, NULL);
pthread_detach (tid);
int error = pthread_join (tid, NULL);
if (error){
printf ("pthread_join: %s\n", strerror (error));
}
int i;
for (i = 0; i < 200; ++i) {
putchar ('+');
usleep (50000);
}
printf ("\n");
return 0;
}
/*
* cancle.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void elapse (void) {
size_t i;
for (i = 0; i < 800000000; ++i);
}
void* thread_proc (void* arg) {
/*
pthread_setcancelstate ( PTHREAD_CANCEL_DISABLE, NULL);
*/
pthread_setcanceltype ( PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
for (;;) {
printf ("我是快乐的子线程!\n");
elapse ();
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
pthread_t tid;
pthread_create (&tid, NULL, thread_proc, NULL);
getchar ();
int error = pthread_cancel (tid);
if (error){
printf ("pthread_cancel: %s\n", strerror (error));
}
pthread_join (tid, NULL);
printf ("子线程终止!\n");
return 0;
}
/*
* udpcli.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main (int argc, char* argv[]) {
if (argc < 3) {
printf ("用法:%s <IP地址> <端口号>\n", argv[0]);
return -1;
}
printf ("客户机:创建套接字...\n");
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror ("socket");
return -1;
}
printf ("客户机:准备地址并连接...\n");
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (atoi (argv[2]));
addr.sin_addr.s_addr = inet_addr (argv[1]);
/*
if (connect (sockfd,
(struct sockaddr*)&addr,
sizeof (addr)) == -1) {
perror ("connect");
return -1;
}
*/
printf ("客户机:发送数据...\n");
for (;;) {
printf ("> ");
char buf[1024];
gets (buf);
if (! strcmp (buf, "!"))
break;
if (sendto (sockfd, buf,
strlen (buf) + 1, 0,
(struct sockaddr*)&addr,
sizeof (addr)) == -1) {
perror ("sendto");
return -1;
}
if (! strcmp (buf, "!!"))
break;
}
printf ("客户机:关闭套接字...\n");
close (sockfd);
return 0;
}
/*
* tcpcli.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main (int argc, char* argv[])
{
if (argc < 3) {
printf ("用法:%s <IP地址> <端口号>\n", argv[0]);
return 0;
}
printf ("客户机:创建套接字...\n");
int sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror ("socket");
return -1;
}
printf ("客户机:准备地址并连接...\n");
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (atoi (argv[2]));
addr.sin_addr.s_addr = inet_addr (argv[1]);
if (connect (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1) {
perror ("connect");
return -1;
}
printf ("客户机:收发数据...\n");
for (;;) {
printf ("> ");
char buf[1024];
gets (buf);
if (! strcmp (buf, "!")) break;
if (send (sockfd, buf, strlen (buf) + 1, 0) == -1) {
perror ("send");
return -1;
}
memset (buf, 0, sizeof (buf));
ssize_t rb = recv (sockfd, buf, sizeof (buf), 0);
if (rb == -1) {
perror ("recv");
return -1;
}
if (rb == 0) {
printf ("客户机:服务器已宕机!\n");
break;
}
printf ("< %s\n", buf);
}
printf ("客户机:关闭套接字...\n");
close (sockfd);
return 0;
}
/*
* tcpcli.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main (int argc, char* argv[])
{
if (argc < 3) {
printf ("用法:%s <IP地址> <端口号>\n", argv[0]);
return 0;
}
printf ("客户机:创建套接字...\n");
int sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror ("socket");
return -1;
}
printf ("客户机:准备地址并连接...\n");
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (atoi (argv[2]));
addr.sin_addr.s_addr = inet_addr (argv[1]);
if (connect (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1) {
perror ("connect");
return -1;
}
printf ("客户机:收发数据...\n");
for (;;) {
printf ("> ");
char buf[1024];
gets (buf);
if (! strcmp (buf, "!")) break;
if (send (sockfd, buf, strlen (buf) + 1, 0) == -1) {
perror ("send");
return -1;
}
memset (buf, 0, sizeof (buf));
ssize_t rb = recv (sockfd, buf, sizeof (buf), 0);
if (rb == -1) {
perror ("recv");
return -1;
}
if (rb == 0) {
printf ("客户机:服务器已宕机!\n");
break;
}
printf ("< %s\n", buf);
}
printf ("客户机:关闭套接字...\n");
close (sockfd);
return 0;
}
/*
* tcpsvr.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void sigchld (int signum)
{
wait (0);
printf ("回收了一个子进程的尸体!\n");
}
int main (int argc, char* argv[])
{
if (argc < 2) {
printf ("用法:%s <端口号>\n", argv[0]);
return -1;
}
if (signal (SIGCHLD, sigchld) == SIG_ERR) {
perror ("signal");
return -1;
}
printf ("服务器:创建套接字...\n");
int sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror ("socket");
return -1;
}
printf ("服务器:准备地址并绑定...\n");
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (atoi (argv[1]));
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (sockfd, (struct sockaddr*)&addr,
sizeof (addr)) == -1) {
perror ("bind");
return -1;
}
printf ("服务器:监听套接字...\n");
if (listen (sockfd, 1024) == -1) {
perror ("listen");
return -1;
}
for (;;) {
printf ("服务器:等待连接请求...\n");
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
int connfd = accept (sockfd, (struct sockaddr*)&addrcli, &addrlen);
printf ("服务器:接受来自%s:%u客户机的连接请求。\n",
inet_ntoa (addrcli.sin_addr),
ntohs (addrcli.sin_port));
pid_t pid = fork ();
if (pid == -1) {
perror ("fork");
return -1;
}
if (pid == 0) {
printf ("服务器:收发数据...\n");
for (;;) {
char buf[1024];
ssize_t rb = recv (connfd, buf, sizeof (buf), 0);
if (rb == -1) {
perror ("recv");
return -1;
}
if (rb == 0) {
printf ("服务器:客户机已关闭连接。\n");
break;
}
if (send (connfd, buf, rb, 0) == -1) {
perror ("send");
return -1;
}
}
printf ("服务器:关闭套接字...\n");
close (connfd);
return 0;
}
}
close (sockfd);
return 0;
}
all:
gcc -m32 -o cancel cancel.c -lpthread
gcc -m32 -o create create.c -lpthread
gcc -m32 -o detach detach.c -lpthread
gcc -m32 -o equal equal.c -lpthread
gcc -m32 -o exit exit.c -lpthread
gcc -m32 -o join join.c -lpthread
gcc -m32 -o tcpcli tcpcli.c
gcc -m32 -o tcpsvr tcpsvr.c
gcc -m32 -o udpcli udpcli.c
gcc -m32 -o udpsvr udpsvr.c
clean:
rm -rf cancel \
create \
detach \
equal \
exit \
join \
tcpcli \
tcpsvr \
udpcli \
udpsvr