Thread: Threads other than pthreads?

  1. #1
    Registered User
    Join Date
    May 2010
    Posts
    269

    Threads other than pthreads?

    I'm not asking for homework or project help, but I came across this
    CS 6210 Project 1: GTThreads

    Students have to essentially create their own thread library that's similar to PThreads.

    My question is, how would u create threads in C without using PThreads?

    Is there a basic C thread other than PThreads? How would one even begin to create a Thread structure?????

  2. #2

  3. #3
    Registered User
    Join Date
    May 2010
    Posts
    269
    Quote Originally Posted by Codeplug View Post
    ahh, excellent find. thank you.

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    269
    essentially, one has to use the ucontext.h library.

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by dayalsoap View Post
    essentially, one has to use the ucontext.h library.
    Nope, on linux you can do it using standard (linux) libraries, since threads are actually implemented by the kernel with clone().

    Here's a simple demo using clone for threads and semaphores for locks:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    #include <sched.h>
    
    #define IDKEY 23003
    #define SSZ 16384
    
    struct thrinit {
    	int sid;
    	int tid;
    	int *data;
    };
    
    struct sembuf sopDown = { 
    	.sem_num = 0,	// array index
    	.sem_op = -1,	// signed value! (see below)
    	.sem_flg = 0
    };
    struct sembuf sopUp = { 0, 1, 0 };
    
    int thread (void *arg) {
    	struct thrinit *me = arg;
    	int i, r;
    	fprintf(stderr,"Start %d (count %d)\n",me->tid,*(me->data));
    	for (i=0;;i++) {
    		semop(me->sid,&sopDown,1);
    		r = semctl(me->sid,0,GETVAL);
    		if (*(me->data)>9) {
    			semop(me->sid,&sopUp,1);
    			break;
    		}
    		(*(me->data))++;
    		fprintf(stderr,"Thread %d-%d: count now %d sem_val=%d\n",me->tid,i,*(me->data),r);
    		semop(me->sid,&sopUp,1);
    	}
    	return 0;
    }
    
    int main(int argc, const char *argv[]) {
    	unsigned char *stacks[3];
    	struct thrinit threads[3];
    	int id = semget(IDKEY, 1, IPC_CREAT|0666),
    		i, count = 0;
    
    	if (id < 0) {
    		perror("semget() failed: ");
    		return -1;
    	}
    
    	semctl(id,0,SETVAL,1);
    /* Confusing fact about sem value and the "sem_op" used by sopDown:
     * one is unsigned, and the other is not. Up/down involves a comparison of 
     * ABSOLUTE values, then combination/subtraction.  Qv. the open group man page for semop() */
    
    	for (i=0;i<3;i++) {
    		threads[i].sid = id;
    		threads[i].tid = i;
    		threads[i].data = &count;
    		stacks[i] = malloc(SSZ);
    		clone(thread,stacks[i]+SSZ-1,CLONE_VM|CLONE_SYSVSEM,(void*)&threads[i]);
    		fprintf(stderr, "issued %d\n", i);
    	}
    
    	while (1) {
    		sleep(1);
    		semop(id,&sopDown,1);
    		fprintf(stderr, "main(): count now %d\n",count);
    		if (count >= 9) break;
    		semop(id,&sopUp,1);
    	}
    	semop(id,&sopUp,1);
    
    	for (i=0;i<3;i++) free(stacks[i]);
    
    	return 0;
    }
    Output should be something like this:

    issued 0
    Start 1 (count 0)
    Start 0 (count 0)
    Thread 1-0: count now 1 sem_val=0
    issued 1
    Thread 0-0: count now 2 sem_val=0
    Start 2 (count 1)
    issued 2
    Thread 1-1: count now 3 sem_val=0
    Thread 2-0: count now 4 sem_val=0
    Thread 0-1: count now 5 sem_val=0
    Thread 1-2: count now 6 sem_val=0
    Thread 2-1: count now 7 sem_val=0
    Thread 0-2: count now 8 sem_val=0
    Thread 1-3: count now 9 sem_val=0
    Thread 2-2: count now 10 sem_val=0
    main(): count now 10

    altho as with all threads, there is no guarantee of the order of exectution. Sorry I was skimpy with the comments, if you are interested ask questions and I can explain.
    Last edited by MK27; 05-27-2010 at 05:20 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    By "standard" of course you mean "standard unix libraries", not "standard C".


    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by quzah View Post
    By "standard" of course you mean "standard unix libraries", not "standard C".
    Yeah, pardon me. Really what I meant was, here's the simplest thread implementation yer ever going to see.

    Those may in fact be linux specific -- POSIX promises only pthreads, not anything about how that happens. But on linux, specifically, it's via clone(). However that will work on any and all linux systems, since clone and semaphores are essential to the kernel.
    Last edited by MK27; 05-27-2010 at 05:23 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    Registered User
    Join Date
    May 2010
    Posts
    269
    This is all excellent stuff guys. Thank you all for the help! I will try this clone solution out and see how it works. definitely, if I'm stuck, I will let you know.


    Quote Originally Posted by MK27 View Post
    Nope, on linux you can do it using standard (linux) libraries, since threads are actually implemented by the kernel with clone().

    Here's a simple demo using clone for threads and semaphores for locks:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    #include <sched.h>
    
    #define IDKEY 23003
    #define SSZ 16384
    
    struct thrinit {
    	int sid;
    	int tid;
    	int *data;
    };
    
    struct sembuf sopDown = { 
    	.sem_num = 0,	// array index
    	.sem_op = -1,	// signed value! (see below)
    	.sem_flg = 0
    };
    struct sembuf sopUp = { 0, 1, 0 };
    
    int thread (void *arg) {
    	struct thrinit *me = arg;
    	int i, r;
    	fprintf(stderr,"Start %d (count %d)\n",me->tid,*(me->data));
    	for (i=0;;i++) {
    		semop(me->sid,&sopDown,1);
    		r = semctl(me->sid,0,GETVAL);
    		if (*(me->data)>9) {
    			semop(me->sid,&sopUp,1);
    			break;
    		}
    		(*(me->data))++;
    		fprintf(stderr,"Thread %d-%d: count now %d sem_val=%d\n",me->tid,i,*(me->data),r);
    		semop(me->sid,&sopUp,1);
    	}
    	return 0;
    }
    
    int main(int argc, const char *argv[]) {
    	unsigned char *stacks[3];
    	struct thrinit threads[3];
    	int id = semget(IDKEY, 1, IPC_CREAT|0666),
    		i, count = 0;
    
    	if (id < 0) {
    		perror("semget() failed: ");
    		return -1;
    	}
    
    	semctl(id,0,SETVAL,1);
    /* Confusing fact about sem value and the "sem_op" used by sopDown:
     * one is unsigned, and the other is not. Up/down involves a comparison of 
     * ABSOLUTE values, then combination/subtraction.  Qv. the open group man page for semop() */
    
    	for (i=0;i<3;i++) {
    		threads[i].sid = id;
    		threads[i].tid = i;
    		threads[i].data = &count;
    		stacks[i] = malloc(SSZ);
    		clone(thread,stacks[i]+SSZ-1,CLONE_VM|CLONE_SYSVSEM,(void*)&threads[i]);
    		fprintf(stderr, "issued %d\n", i);
    	}
    
    	while (1) {
    		sleep(1);
    		semop(id,&sopDown,1);
    		fprintf(stderr, "main(): count now %d\n",count);
    		if (count >= 9) break;
    		semop(id,&sopUp,1);
    	}
    	semop(id,&sopUp,1);
    
    	for (i=0;i<3;i++) free(stacks[i]);
    
    	return 0;
    }
    Output should be something like this:

    issued 0
    Start 1 (count 0)
    Start 0 (count 0)
    Thread 1-0: count now 1 sem_val=0
    issued 1
    Thread 0-0: count now 2 sem_val=0
    Start 2 (count 1)
    issued 2
    Thread 1-1: count now 3 sem_val=0
    Thread 2-0: count now 4 sem_val=0
    Thread 0-1: count now 5 sem_val=0
    Thread 1-2: count now 6 sem_val=0
    Thread 2-1: count now 7 sem_val=0
    Thread 0-2: count now 8 sem_val=0
    Thread 1-3: count now 9 sem_val=0
    Thread 2-2: count now 10 sem_val=0
    main(): count now 10

    altho as with all threads, there is no guarantee of the order of exectution. Sorry I was skimpy with the comments, if you are interested ask questions and I can explain.

  9. #9
    Registered User jeffcobb's Avatar
    Join Date
    Dec 2009
    Location
    Henderson, NV
    Posts
    875
    To add something to the mix: I have often thought of the idea that if you write your own thread scheduling, you can track context switches. As anyone who has done some of this coding knows that for any given task, one sequence of contetx switches allows the take to perform properly; another might reasult in deadlock or worse. I have had the thought that if you could record these switches and you see that the job gets done right, you could feed these switches back into the scheduler to ensure consistent thread execution time after time. How many times have you written a multithreaded app that runs well in dev but crashes at the client site. Something like this would ensure the program would act the same outside the lab as inside...
    C/C++ Environment: GNU CC/Emacs
    Make system: CMake
    Debuggers: Valgrind/GDB

  10. #10
    Registered User
    Join Date
    May 2010
    Posts
    269
    Isn't there a formal proof to show that an algorithm has deadlock freedom?

  11. #11
    Registered User
    Join Date
    May 2010
    Posts
    1

    searching

    Quote Originally Posted by MK27 View Post
    Nope, on linux you can do it using standard (linux) libraries, since threads are actually implemented by the kernel with clone().

    Here's a simple demo using clone for threads and semaphores for locks:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    #include <sched.h>
    
    #define IDKEY 23003
    #define SSZ 16384
    
    struct thrinit {
    	int sid;
    	int tid;
    	int *data;
    };
    
    struct sembuf sopDown = { 
    	.sem_num = 0,	// array index
    	.sem_op = -1,	// signed value! (see below)
    	.sem_flg = 0
    };
    struct sembuf sopUp = { 0, 1, 0 };
    
    int thread (void *arg) {
    	struct thrinit *me = arg;
    	int i, r;
    	fprintf(stderr,"Start %d (count %d)\n",me->tid,*(me->data));
    	for (i=0;;i++) {
    		semop(me->sid,&sopDown,1);
    		r = semctl(me->sid,0,GETVAL);
    		if (*(me->data)>9) {
    			semop(me->sid,&sopUp,1);
    			break;
    		}
    		(*(me->data))++;
    		fprintf(stderr,"Thread %d-%d: count now %d sem_val=%d\n",me->tid,i,*(me->data),r);
    		semop(me->sid,&sopUp,1);
    	}
    	return 0;
    }
    
    int main(int argc, const char *argv[]) {
    	unsigned char *stacks[3];
    	struct thrinit threads[3];
    	int id = semget(IDKEY, 1, IPC_CREAT|0666),
    		i, count = 0;
    
    	if (id < 0) {
    		perror("semget() failed: ");
    		return -1;
    	}
    
    	semctl(id,0,SETVAL,1);
    /* Confusing fact about sem value and the "sem_op" used by sopDown:
     * one is unsigned, and the other is not. Up/down involves a comparison of 
     * ABSOLUTE values, then combination/subtraction.  Qv. the open group man page for semop() */
    
    	for (i=0;i<3;i++) {
    		threads[i].sid = id;
    		threads[i].tid = i;
    		threads[i].data = &count;
    		stacks[i] = malloc(SSZ);
    		clone(thread,stacks[i]+SSZ-1,CLONE_VM|CLONE_SYSVSEM,(void*)&threads[i]);
    		fprintf(stderr, "issued %d\n", i);
    	}
    
    	while (1) {
    		sleep(1);
    		semop(id,&sopDown,1);
    		fprintf(stderr, "main(): count now %d\n",count);
    		if (count >= 9) break;
    		semop(id,&sopUp,1);
    	}
    	semop(id,&sopUp,1);
    
    	for (i=0;i<3;i++) free(stacks[i]);
    
    	return 0;
    }
    Output should be something like this:

    issued 0
    Start 1 (count 0)
    Start 0 (count 0)
    Thread 1-0: count now 1 sem_val=0
    issued 1
    Thread 0-0: count now 2 sem_val=0
    Start 2 (count 1)
    issued 2
    Thread 1-1: count now 3 sem_val=0
    Thread 2-0: count now 4 sem_val=0
    Thread 0-1: count now 5 sem_val=0
    Thread 1-2: count now 6 sem_val=0
    Thread 2-1: count now 7 sem_val=0
    Thread 0-2: count now 8 sem_val=0
    Thread 1-3: count now 9 sem_val=0
    Thread 2-2: count now 10 sem_val=0
    main(): count now 10

    altho as with all threads, there is no guarantee of the order of exectution. Sorry I was skimpy with the comments, if you are interested ask questions and I can explain.



    I find out that there is scarceness of C programming book of multithread and IPC for Window programming. I wonder if someone has some such books and could you send it to me?.I'm searching for multithread and IPC for window programmig in C language. Can anyone help me?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Producer/Consumer - problems creating threads
    By hansel13 in forum C Programming
    Replies: 47
    Last Post: 08-20-2010, 02:02 PM
  2. Need Help: Multi-threading and Synchronization
    By Anom in forum C Programming
    Replies: 7
    Last Post: 12-08-2009, 05:34 PM
  3. Replies: 5
    Last Post: 10-17-2008, 11:28 AM
  4. problem with win32 threads
    By pdmarshall in forum C++ Programming
    Replies: 6
    Last Post: 07-29-2004, 02:39 PM
  5. Block and wake up certain threads
    By Spark in forum C Programming
    Replies: 9
    Last Post: 06-01-2002, 03:39 AM