附:msgid_ds结构定义如下: struct msgid_ds
{struct ipc_perm msg_perm; /*许可权结构*/ shot padl[7]; /*由系统使用*/ ushort onsg_qnum; /*队列上消息数*/ ushort msg_qbytes; /*队列上最大字节数*/ ushort msg_lspid; ushort msg_lrpid;
/*最后发送消息的PID*/ /*最后接收消息的PID*/ /*最后发送消息的时间*/ /*最后接收消息的时间*/
time_t msg__stime; time_t msg_rtime; me_t msg_ctime; };
struct ipc_perm {ushort uid;
/*最后更改时间*/
/*当前用户id*/ /*当前进程组id*/ /*创建用户id*/ /*创建进程组id*/ /*存取许可权*/
ushort gid;
ushort cuid;
ushort cgid ushort mode;
{shot patl;long pad2} /*由系统使用*/ };
例:使用系统调用msgget( ), msgsnd( ), msgrcv( )及msgctl()编制一长度为1K
的消息发送和接收的程序 。
(1)为了便于操作和观察结果,用一个程序为“引子”,先后fork( )两个子进程,SERVER和CLIENT,进行通信。
(2)SERVER端建立一个Key为75的消息队列,等待其他进程发来的消息。当遇到类型为1的消息,则作为结束信号,取消该队列,并退出SERVER 。SERVER每接收到一个消息后显示一句“(server)received”。
(3)CLIENT端使用Key为75的消息队列,先后发送类型从10到1的消息,然后退出。最后的一个消息,既是 SERVER端需要的结束信号。CLIENT每发
29
送一条消息后显示一句“(client)sent”。
(4)父进程在 SERVER和 CLIENT均退出后结束。 参考程序:
#include
#define MSGKEY 75 /*定义关键词MEGKEY*/ struct msgform /*消息结构*/ { long mtype; char mtxt[1030]; /*文本长度*/ }msg;
int msgqid,i;
void CLIENT( ) { int i; msgqid=msgget(MSGKEY,0777); for(i=10;i>=1;i--) { msg.mtype=i; printf(\ msgsnd(msgqid,&msg,1024,0); /*发送消息msg入msgid消息队列*/ } exit(0); }
void SERVER( ) {
msgqid=msgget(MSGKEY,0777|IPC_CREAT); /*由关键字获得消息队列*/ do { msgrcv(msgqid,&msg,1030,0,0); /*从队列msgid接受消息msg*/ printf(\
}while(msg.mtype!=1); /*消息类型为1时,释放队列*/ msgctl(msgqid, IPC_RMID,0); exit(0); }
main() {
if(fork()) SERVER();
30
}
else CLIENT( ); wait(0); wait(0);
<结果>
从理想的结果来说,应当是每当Client发送一个消息后,server接收该消息,Client再发送下一条。也就是说“(Client)sent”和“(server)received”的字样应该在屏幕上交替出现。实际的结果大多是,先由 Client 发送两条消息,然后Server接收一条消息。此后Client、Server交替发送和接收消息,最后一次接收两条消息,Client 和Server 分别发送和接收了10条消息,与预期设想一致。 <分析>
message的传送和控制并不保证完全同步,当一个程序不再激活状态的时候,它完全可能继续睡眠,造成上面现象,在多次send message 后才 receive message.这一点有助于理解消息转送的实现机理。
实验五 Linux下多线程编程
5.1 linux多线程编程常用函数 1.创建缺省线程
int pthread_create(pthread_t *thread,pthread_attr_t *attr, void*(*start_routine), void *arg); 参数:
? thread 线程标识符 ? attr 线程属性设置
? start_routine 线程函数起始地址 ? arg 传递给start_routine的参数
当pthread_create() 成功时,所创建线程的ID 被存储在由thread指向的位置中。第二个参数用于设置线程属性,如果不需要特殊的属性,可以简单的设置该参数为NULL,最后两个参数告诉线程将要启动执行的函数和传递给该函数的参数。调用成功完成后返回0,其他的值都表示出现错误。 2.终止线程
31
一个线程的结束有两种途径,一种是线程函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit实现 。
void pthread_exit (void *__retval)
唯一的参数是函数的返回代码 。如果pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return。
一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。 3. 等待线程终止用(等待一个线程的结束)
int pthread_join(thread_t tid, void **status); 参数:
第一个参数为被等待的线程标识符 。
第二个参数为一个用户定义的指针,用来存储被等待线程返回值。 这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。 返回值:
调用成功完成后,pthread_join() 将返回0。其他任何返回值都表示出现了错误。
4、线程标识符pthread_t
pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义: typedef unsigned long int pthread_t; ? 用来标识一个线程 5、线程属性pthread_attr_t
使用pthread_create函数创建线程时,线程参数一般都为默认值,即将第二个参数设为NULL ,对大多数程序来说,使用默认属性就够了。
属性结构为pthread_attr_t,它在头文件/usr/include/pthread.h中定义,属性值不能直接设置,须使用相关函数进行操作,初始化的函数为pthread_attr_init,这个函数必须在pthread_create函数之前调用。
32
5.2 多线程示例
? 编写Linux下的多线程程序,需要使用头文件pthread.h ? 多线程程序实例1
/* example.c*/ #include
int i;
for(i=0;i<3;i++)
printf(\}
int main(void) {
pthread_t id; int ret;
ret=pthread_create(&id,NULL,thread,NULL); if (ret!=0){
printf (\ exit (1); }
int i;
for (i=0;i<3;i++)
printf (\ pthread_join(id, NULL); return(0); }
执行:gcc example.c -lpthread -o example 或者:gcc -g -c example.c
gcc example.o -lpthread -o example
运行example1,我们得到如下结果: This is the main process. This is a pthread. This is the main process. This is the main process. This is a pthread. This is a pthread.
33